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 WLog_ERR(TAG,
"planar->maxWidth %" PRIu32
" < nSrcWidth %" PRIu32, planar->maxWidth,
750 if (planar->maxHeight < nSrcHeight)
752 WLog_ERR(TAG,
"planar->maxHeight %" PRIu32
" < nSrcHeight %" PRIu32, planar->maxHeight,
757 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
759 nDstStep = nDstWidth * bpp;
761 const BYTE* srcp = pSrcData;
763 if (!pSrcData || (SrcSize < 1))
765 WLog_ERR(TAG,
"Invalid argument pSrcData=%p [size=%" PRIu32
"]",
766 WINPR_CXX_COMPAT_CAST(
const void*, pSrcData), SrcSize);
772 WLog_ERR(TAG,
"Invalid argument pDstData=nullptr");
776 const BYTE FormatHeader = *srcp++;
777 const BYTE cll = (FormatHeader & PLANAR_FORMAT_HEADER_CLL_MASK);
778 const BYTE cs = (FormatHeader & PLANAR_FORMAT_HEADER_CS) != 0;
779 const BYTE rle = (FormatHeader & PLANAR_FORMAT_HEADER_RLE) != 0;
780 const BYTE alpha = !(FormatHeader & PLANAR_FORMAT_HEADER_NA);
782 DstFormat = planar_invert_format(planar, alpha, DstFormat);
785 useAlpha = FreeRDPColorHasAlpha(DstFormat);
792 WLog_ERR(TAG,
"Chroma subsampling requires YCoCg and does not work with RGB data");
796 const UINT32 subWidth = (nSrcWidth / 2) + (nSrcWidth % 2);
797 const UINT32 subHeight = (nSrcHeight / 2) + (nSrcHeight % 2);
798 const UINT32 planeSize = nSrcWidth * nSrcHeight;
799 const UINT32 subSize = subWidth * subHeight;
803 rawSizes[0] = planeSize;
804 rawWidths[0] = nSrcWidth;
805 rawHeights[0] = nSrcHeight;
806 rawSizes[1] = planeSize;
807 rawWidths[1] = nSrcWidth;
808 rawHeights[1] = nSrcHeight;
809 rawSizes[2] = planeSize;
810 rawWidths[2] = nSrcWidth;
811 rawHeights[2] = nSrcHeight;
812 rawSizes[3] = planeSize;
813 rawWidths[3] = nSrcWidth;
814 rawHeights[3] = nSrcHeight;
818 rawSizes[0] = planeSize;
819 rawWidths[0] = nSrcWidth;
820 rawHeights[0] = nSrcHeight;
821 rawSizes[1] = subSize;
822 rawWidths[1] = subWidth;
823 rawHeights[1] = subHeight;
824 rawSizes[2] = subSize;
825 rawWidths[2] = subWidth;
826 rawHeights[2] = subHeight;
827 rawSizes[3] = planeSize;
828 rawWidths[3] = nSrcWidth;
829 rawHeights[3] = nSrcHeight;
832 const size_t diff = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(srcp - pSrcData));
835 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
842 UINT32 base = planeSize * 3;
844 base = planeSize + planeSize / 2;
848 if ((SrcSize - diff) < (planeSize + base))
850 WLog_ERR(TAG,
"Alpha plane size mismatch %" PRIuz
" < %" PRIu32, SrcSize - diff,
856 planes[0] = planes[3] + rawSizes[3];
857 planes[1] = planes[0] + rawSizes[0];
858 planes[2] = planes[1] + rawSizes[1];
860 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
862 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p",
863 WINPR_CXX_COMPAT_CAST(
const void*, planes[2]), rawSizes[2],
864 WINPR_CXX_COMPAT_CAST(
const void*, &pSrcData[SrcSize]));
870 if ((SrcSize - diff) < base)
872 WLog_ERR(TAG,
"plane size mismatch %" PRIuz
" < %" PRIu32, SrcSize - diff, base);
877 planes[1] = planes[0] + rawSizes[0];
878 planes[2] = planes[1] + rawSizes[1];
880 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
882 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p",
883 WINPR_CXX_COMPAT_CAST(
const void*, planes[2]), rawSizes[2],
884 WINPR_CXX_COMPAT_CAST(
const void*, &pSrcData[SrcSize]));
894 rleSizes[3] = planar_skip_plane_rle(planes[3], (UINT32)(SrcSize - diff), rawWidths[3],
900 planes[0] = planes[3] + rleSizes[3];
905 const size_t diff0 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[0] - pSrcData));
908 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff0);
911 rleSizes[0] = planar_skip_plane_rle(planes[0], (UINT32)(SrcSize - diff0), rawWidths[0],
917 planes[1] = planes[0] + rleSizes[0];
919 const size_t diff1 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[1] - pSrcData));
922 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff1);
925 rleSizes[1] = planar_skip_plane_rle(planes[1], (UINT32)(SrcSize - diff1), rawWidths[1],
931 planes[2] = planes[1] + rleSizes[1];
932 const size_t diff2 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[2] - pSrcData));
935 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
938 rleSizes[2] = planar_skip_plane_rle(planes[2], (UINT32)(SrcSize - diff2), rawWidths[2],
947 UINT32 TempFormat = 0;
948 BYTE* pTempData = pDstData;
949 UINT32 nTempStep = nDstStep;
950 UINT32 nTotalHeight = nYDst + nDstHeight;
953 TempFormat = PIXEL_FORMAT_BGRA32;
955 TempFormat = PIXEL_FORMAT_BGRX32;
957 TempFormat = planar_invert_format(planar, alpha, TempFormat);
959 if ((TempFormat != DstFormat) || (nSrcWidth != nDstWidth) || (nSrcHeight != nDstHeight))
961 pTempData = planar->pTempData;
962 nTempStep = planar->nTempStep;
963 nTotalHeight = planar->maxHeight;
968 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
969 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
973 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
975 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
977 if ((SrcSize - (srcp - pSrcData)) == 1)
982 if (nYDst + nSrcHeight > nTotalHeight)
985 "planar plane destination Y %" PRIu32
" + height %" PRIu32
986 " exceeds totalHeight %" PRIu32,
987 nYDst, nSrcHeight, nTotalHeight);
991 if ((nXDst + nSrcWidth) * bpp > nTempStep)
994 "planar plane destination (X %" PRIu32
" + width %" PRIu32
995 ") * bpp %" PRIu32
" exceeds stride %" PRIu32,
996 nXDst, nSrcWidth, bpp, nTempStep);
1000 status = planar_decompress_plane_rle(
1001 planes[0], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[0]), pTempData, nTempStep,
1002 nXDst, nYDst, nSrcWidth, nSrcHeight, 2, vFlip);
1007 status = planar_decompress_plane_rle(
1008 planes[1], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[1]), pTempData, nTempStep,
1009 nXDst, nYDst, nSrcWidth, nSrcHeight, 1, vFlip);
1014 status = planar_decompress_plane_rle(
1015 planes[2], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[2]), pTempData, nTempStep,
1016 nXDst, nYDst, nSrcWidth, nSrcHeight, 0, vFlip);
1021 srcp += rleSizes[0] + rleSizes[1] + rleSizes[2];
1025 status = planar_decompress_plane_rle(
1026 planes[3], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[3]), pTempData,
1027 nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 3, vFlip);
1030 status = planar_set_plane(0xFF, pTempData, nTempStep, nXDst, nYDst, nSrcWidth,
1031 nSrcHeight, 3, vFlip);
1037 srcp += rleSizes[3];
1040 if (pTempData != pDstData)
1042 if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, w, h,
1043 pTempData, TempFormat, nTempStep, nXDst, nYDst,
1044 nullptr, FREERDP_FLIP_NONE))
1046 WLog_ERR(TAG,
"planar image copy failed");
1053 UINT32 TempFormat = 0;
1054 BYTE* pTempData = planar->pTempData;
1055 UINT32 nTempStep = planar->nTempStep;
1056 UINT32 nTotalHeight = planar->maxHeight;
1057 BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
1060 TempFormat = PIXEL_FORMAT_BGRA32;
1062 TempFormat = PIXEL_FORMAT_BGRX32;
1066 WLog_ERR(TAG,
"pTempData == NULL");
1072 BYTE* rleBuffer[4] = WINPR_C_ARRAY_INIT;
1074 if (!planar->rlePlanesBuffer)
1076 WLog_ERR(TAG,
"planar->rlePlanesBuffer == NULL");
1080 rleBuffer[3] = planar->rlePlanesBuffer;
1081 rleBuffer[0] = rleBuffer[3] + planeSize;
1082 rleBuffer[1] = rleBuffer[0] + planeSize;
1083 rleBuffer[2] = rleBuffer[1] + planeSize;
1086 status = planar_decompress_plane_rle_only(
1087 planes[3], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[3]), rleBuffer[3],
1088 rawWidths[3], rawHeights[3]);
1095 srcp += rleSizes[3];
1097 status = planar_decompress_plane_rle_only(
1098 planes[0], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[0]), rleBuffer[0],
1099 rawWidths[0], rawHeights[0]);
1104 status = planar_decompress_plane_rle_only(
1105 planes[1], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[1]), rleBuffer[1],
1106 rawWidths[1], rawHeights[1]);
1111 status = planar_decompress_plane_rle_only(
1112 planes[2], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[2]), rleBuffer[2],
1113 rawWidths[2], rawHeights[2]);
1118 planes[0] = rleBuffer[0];
1119 planes[1] = rleBuffer[1];
1120 planes[2] = rleBuffer[2];
1121 planes[3] = rleBuffer[3];
1130 if (!planar_subsample_expand(planes[1], rawSizes[1], nSrcWidth, nSrcHeight,
1131 rawWidths[1], rawHeights[1], planar->deltaPlanes[0]))
1134 planes[1] = planar->deltaPlanes[0];
1135 rawSizes[1] = planeSize;
1136 rawWidths[1] = nSrcWidth;
1137 rawHeights[1] = nSrcHeight;
1139 if (!planar_subsample_expand(planes[2], rawSizes[2], nSrcWidth, nSrcHeight,
1140 rawWidths[2], rawHeights[2], planar->deltaPlanes[1]))
1143 planes[2] = planar->deltaPlanes[1];
1144 rawSizes[2] = planeSize;
1145 rawWidths[2] = nSrcWidth;
1146 rawHeights[2] = nSrcHeight;
1149 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
1150 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
1154 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
1156 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
1158 if ((SrcSize - (srcp - pSrcData)) == 1)
1162 WINPR_ASSERT(prims->YCoCgToRGB_8u_AC4R);
1163 int rc = prims->YCoCgToRGB_8u_AC4R(
1164 pTempData, WINPR_ASSERTING_INT_CAST(int32_t, nTempStep), dst, DstFormat,
1165 WINPR_ASSERTING_INT_CAST(int32_t, nDstStep), w, h, cll, useAlpha);
1166 if (rc != PRIMITIVES_SUCCESS)
1168 WLog_ERR(TAG,
"YCoCgToRGB_8u_AC4R failed with %d", rc);
1177static inline BOOL freerdp_split_color_planes(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
1178 const BYTE* WINPR_RESTRICT data, UINT32 format,
1179 UINT32 width, UINT32 height, UINT32 scanline,
1180 BYTE* WINPR_RESTRICT planes[4])
1182 WINPR_ASSERT(planar);
1184 if ((width > INT32_MAX) || (height > INT32_MAX) || (scanline > INT32_MAX))
1188 scanline = width * FreeRDPGetBytesPerPixel(format);
1190 if (planar->topdown)
1193 for (UINT32 i = 0; i < height; i++)
1195 const BYTE* pixel = &data[1ULL * scanline * i];
1197 for (UINT32 j = 0; j < width; j++)
1199 const UINT32 color = FreeRDPReadColor(pixel, format);
1200 pixel += FreeRDPGetBytesPerPixel(format);
1201 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1202 &planes[0][k],
nullptr);
1211 for (INT64 i = (INT64)height - 1; i >= 0; i--)
1213 const BYTE* pixel = &data[1ULL * scanline * (UINT32)i];
1215 for (UINT32 j = 0; j < width; j++)
1217 const UINT32 color = FreeRDPReadColor(pixel, format);
1218 pixel += FreeRDPGetBytesPerPixel(format);
1219 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1220 &planes[0][k],
nullptr);
1228static inline UINT32 freerdp_bitmap_planar_write_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1229 UINT32 cRawBytes, UINT32 nRunLength,
1230 BYTE* WINPR_RESTRICT pOutBuffer,
1231 UINT32 outBufferSize)
1233 const BYTE* pInput = pInBuffer;
1234 BYTE* pOutput = pOutBuffer;
1235 BYTE controlByte = 0;
1236 UINT32 nBytesToWrite = 0;
1238 if (!cRawBytes && !nRunLength)
1243 cRawBytes += nRunLength;
1251 if (nRunLength > 15)
1253 if (nRunLength < 18)
1255 controlByte = PLANAR_CONTROL_BYTE(13, cRawBytes);
1261 controlByte = PLANAR_CONTROL_BYTE(15, cRawBytes);
1268 controlByte = PLANAR_CONTROL_BYTE(nRunLength, cRawBytes);
1275 controlByte = PLANAR_CONTROL_BYTE(0, 15);
1279 if (outBufferSize < 1)
1283 *pOutput = controlByte;
1285 nBytesToWrite = (controlByte >> 4);
1289 if (outBufferSize < nBytesToWrite)
1292 outBufferSize -= nBytesToWrite;
1293 CopyMemory(pOutput, pInput, nBytesToWrite);
1294 pOutput += nBytesToWrite;
1295 pInput += nBytesToWrite;
1301 if (nRunLength > 47)
1303 if (nRunLength < 50)
1305 controlByte = PLANAR_CONTROL_BYTE(2, 13);
1310 controlByte = PLANAR_CONTROL_BYTE(2, 15);
1314 else if (nRunLength > 31)
1316 controlByte = PLANAR_CONTROL_BYTE(2, (nRunLength - 32));
1319 else if (nRunLength > 15)
1321 controlByte = PLANAR_CONTROL_BYTE(1, (nRunLength - 16));
1326 controlByte = PLANAR_CONTROL_BYTE(nRunLength, 0);
1330 if (outBufferSize < 1)
1334 *pOutput = controlByte;
1338 const intptr_t diff = (pOutput - pOutBuffer);
1339 if ((diff < 0) || (diff > UINT32_MAX))
1341 return (UINT32)diff;
1344static inline UINT32 freerdp_bitmap_planar_encode_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1345 UINT32 inBufferSize,
1346 BYTE* WINPR_RESTRICT pOutBuffer,
1347 UINT32 outBufferSize)
1350 const BYTE* pInput = pInBuffer;
1351 BYTE* pOutput = pOutBuffer;
1352 const BYTE* pBytes =
nullptr;
1353 UINT32 cRawBytes = 0;
1354 UINT32 nRunLength = 0;
1355 UINT32 nBytesWritten = 0;
1356 UINT32 nTotalBytesWritten = 0;
1366 const UINT32 bSymbolMatch = (symbol == *pInput) != 0;
1371 if (nRunLength && !bSymbolMatch)
1375 cRawBytes += nRunLength;
1380 pBytes = pInput - (cRawBytes + nRunLength + 1);
1381 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1382 pOutput, outBufferSize);
1385 if (!nBytesWritten || (nBytesWritten > outBufferSize))
1388 nTotalBytesWritten += nBytesWritten;
1389 outBufferSize -= nBytesWritten;
1390 pOutput += nBytesWritten;
1395 nRunLength += bSymbolMatch;
1396 cRawBytes += (!bSymbolMatch) != 0;
1397 }
while (outBufferSize);
1399 if (cRawBytes || nRunLength)
1401 pBytes = pInput - (cRawBytes + nRunLength);
1402 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1403 pOutput, outBufferSize);
1408 nTotalBytesWritten += nBytesWritten;
1414 return nTotalBytesWritten;
1417BOOL freerdp_bitmap_planar_compress_plane_rle(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1418 UINT32 height, BYTE* WINPR_RESTRICT outPlane,
1419 UINT32* WINPR_RESTRICT dstSize)
1425 const BYTE* pInput = inPlane;
1426 BYTE* pOutput = outPlane;
1427 UINT32 outBufferSize = *dstSize;
1428 UINT32 nTotalBytesWritten = 0;
1430 while (outBufferSize > 0)
1432 const UINT32 nBytesWritten =
1433 freerdp_bitmap_planar_encode_rle_bytes(pInput, width, pOutput, outBufferSize);
1435 if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
1438 outBufferSize -= nBytesWritten;
1439 nTotalBytesWritten += nBytesWritten;
1440 pOutput += nBytesWritten;
1444 if (index >= height)
1448 *dstSize = nTotalBytesWritten;
1452static inline BOOL freerdp_bitmap_planar_compress_planes_rle(BYTE* WINPR_RESTRICT inPlanes[4],
1453 UINT32 width, UINT32 height,
1454 BYTE* WINPR_RESTRICT outPlanes,
1455 UINT32* WINPR_RESTRICT dstSizes,
1458 UINT32 outPlanesSize = width * height * 4;
1467 dstSizes[0] = outPlanesSize;
1469 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[0], width, height, outPlanes,
1473 outPlanes += dstSizes[0];
1474 outPlanesSize -= dstSizes[0];
1478 dstSizes[1] = outPlanesSize;
1480 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[1], width, height, outPlanes,
1484 outPlanes += dstSizes[1];
1485 outPlanesSize -= dstSizes[1];
1487 dstSizes[2] = outPlanesSize;
1489 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[2], width, height, outPlanes,
1493 outPlanes += dstSizes[2];
1494 outPlanesSize -= dstSizes[2];
1496 dstSizes[3] = outPlanesSize;
1498 return (freerdp_bitmap_planar_compress_plane_rle(inPlanes[3], width, height, outPlanes,
1502BYTE* freerdp_bitmap_planar_delta_encode_plane(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1503 UINT32 height, BYTE* WINPR_RESTRICT outPlane)
1507 if (width * height == 0)
1510 outPlane = (BYTE*)calloc(height, width);
1516 CopyMemory(outPlane, inPlane, width);
1518 for (UINT32 y = 1; y < height; y++)
1520 const size_t off = 1ull * width * y;
1521 BYTE* outPtr = &outPlane[off];
1522 const BYTE* srcPtr = &inPlane[off];
1523 const BYTE* prevLinePtr = &inPlane[off - width];
1524 for (UINT32 x = 0; x < width; x++)
1526 const int delta = (int)srcPtr[x] - (
int)prevLinePtr[x];
1527 const int s2c1i = (delta >= 0) ? delta : (INT_MAX + delta) + 1;
1528 const int8_t s2c1 = WINPR_CXX_COMPAT_CAST(int8_t, s2c1i);
1529 const uint32_t s2c =
1530 (s2c1 >= 0) ? ((UINT32)s2c1 << 1) : (((UINT32)(~(s2c1) + 1) << 1) - 1);
1531 outPtr[x] = (BYTE)s2c;
1538static inline BOOL freerdp_bitmap_planar_delta_encode_planes(BYTE* WINPR_RESTRICT inPlanes[4],
1539 UINT32 width, UINT32 height,
1540 BYTE* WINPR_RESTRICT outPlanes[4])
1542 for (UINT32 i = 0; i < 4; i++)
1545 freerdp_bitmap_planar_delta_encode_plane(inPlanes[i], width, height, outPlanes[i]);
1554BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1555 const BYTE* WINPR_RESTRICT data, UINT32 format, UINT32 width,
1556 UINT32 height, UINT32 scanline, BYTE* WINPR_RESTRICT dstData,
1557 UINT32* WINPR_RESTRICT pDstSize)
1560 BYTE* dstp =
nullptr;
1561 UINT32 dstSizes[4] = WINPR_C_ARRAY_INIT;
1562 BYTE FormatHeader = 0;
1564 if (!context || !context->rlePlanesBuffer)
1567 if (context->AllowSkipAlpha)
1568 FormatHeader |= PLANAR_FORMAT_HEADER_NA;
1570 const UINT32 planeSize = width * height;
1572 if (!context->AllowSkipAlpha)
1573 format = planar_invert_format(context, TRUE, format);
1575 if (!freerdp_split_color_planes(context, data, format, width, height, scanline,
1579 if (context->AllowRunLengthEncoding)
1581 if (!freerdp_bitmap_planar_delta_encode_planes(context->planes, width, height,
1582 context->deltaPlanes))
1585 if (!freerdp_bitmap_planar_compress_planes_rle(context->deltaPlanes, width, height,
1586 context->rlePlanesBuffer, dstSizes,
1587 context->AllowSkipAlpha))
1591 uint32_t offset = 0;
1592 FormatHeader |= PLANAR_FORMAT_HEADER_RLE;
1593 context->rlePlanes[0] = &context->rlePlanesBuffer[offset];
1594 offset += dstSizes[0];
1595 context->rlePlanes[1] = &context->rlePlanesBuffer[offset];
1596 offset += dstSizes[1];
1597 context->rlePlanes[2] = &context->rlePlanesBuffer[offset];
1598 offset += dstSizes[2];
1599 context->rlePlanes[3] = &context->rlePlanesBuffer[offset];
1601#if defined(WITH_DEBUG_CODECS)
1603 "R: [%" PRIu32
"/%" PRIu32
"] G: [%" PRIu32
"/%" PRIu32
"] B: [%" PRIu32
1605 dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize);
1610 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1612 if (!context->AllowRunLengthEncoding)
1615 if (context->rlePlanes[0] ==
nullptr)
1618 if (context->rlePlanes[1] ==
nullptr)
1621 if (context->rlePlanes[2] ==
nullptr)
1624 if (context->rlePlanes[3] ==
nullptr)
1632 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1634 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1635 size += dstSizes[0];
1640 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1641 size += (dstSizes[1] + dstSizes[2] + dstSizes[3]);
1643 size += (planeSize * 3);
1645 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1648 dstData = malloc(size);
1657 *dstp = FormatHeader;
1662 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1664 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1666 CopyMemory(dstp, context->rlePlanes[0], dstSizes[0]);
1667 dstp += dstSizes[0];
1671 CopyMemory(dstp, context->planes[0], planeSize);
1678 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1680 CopyMemory(dstp, context->rlePlanes[1], dstSizes[1]);
1681 dstp += dstSizes[1];
1685 CopyMemory(dstp, context->planes[1], planeSize);
1691 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1693 CopyMemory(dstp, context->rlePlanes[2], dstSizes[2]);
1694 dstp += dstSizes[2];
1698 CopyMemory(dstp, context->planes[2], planeSize);
1704 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1706 CopyMemory(dstp, context->rlePlanes[3], dstSizes[3]);
1707 dstp += dstSizes[3];
1711 CopyMemory(dstp, context->planes[3], planeSize);
1717 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1723 const intptr_t diff = (dstp - dstData);
1724 if ((diff < 0) || (diff > UINT32_MAX))
1729 size = (UINT32)diff;
1734BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1735 UINT32 width, UINT32 height)
1740 context->bgr = FALSE;
1741 context->maxWidth = PLANAR_ALIGN(width, 4);
1742 context->maxHeight = PLANAR_ALIGN(height, 4);
1744 const UINT64 tmp = (UINT64)context->maxWidth * context->maxHeight;
1745 if (tmp > UINT32_MAX)
1747 context->maxPlaneSize = (UINT32)tmp;
1750 if (context->maxWidth > UINT32_MAX / 4)
1752 context->nTempStep = context->maxWidth * 4;
1754 memset((
void*)context->planes, 0,
sizeof(context->planes));
1755 memset((
void*)context->rlePlanes, 0,
sizeof(context->rlePlanes));
1756 memset((
void*)context->deltaPlanes, 0,
sizeof(context->deltaPlanes));
1758 if (context->maxPlaneSize > 0)
1760 void* tmp = winpr_aligned_recalloc(context->planesBuffer, context->maxPlaneSize, 4, 32);
1763 context->planesBuffer = tmp;
1765 tmp = winpr_aligned_recalloc(context->pTempData, context->maxPlaneSize, 6, 32);
1768 context->pTempData = tmp;
1770 tmp = winpr_aligned_recalloc(context->deltaPlanesBuffer, context->maxPlaneSize, 4, 32);
1773 context->deltaPlanesBuffer = tmp;
1775 tmp = winpr_aligned_recalloc(context->rlePlanesBuffer, context->maxPlaneSize, 4, 32);
1778 context->rlePlanesBuffer = tmp;
1780 context->planes[0] = &context->planesBuffer[0ULL * context->maxPlaneSize];
1781 context->planes[1] = &context->planesBuffer[1ULL * context->maxPlaneSize];
1782 context->planes[2] = &context->planesBuffer[2ULL * context->maxPlaneSize];
1783 context->planes[3] = &context->planesBuffer[3ULL * context->maxPlaneSize];
1784 context->deltaPlanes[0] = &context->deltaPlanesBuffer[0ULL * context->maxPlaneSize];
1785 context->deltaPlanes[1] = &context->deltaPlanesBuffer[1ULL * context->maxPlaneSize];
1786 context->deltaPlanes[2] = &context->deltaPlanesBuffer[2ULL * context->maxPlaneSize];
1787 context->deltaPlanes[3] = &context->deltaPlanesBuffer[3ULL * context->maxPlaneSize];
1792BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, UINT32 maxWidth,
1795 BITMAP_PLANAR_CONTEXT* context =
1796 (BITMAP_PLANAR_CONTEXT*)winpr_aligned_calloc(1,
sizeof(BITMAP_PLANAR_CONTEXT), 32);
1801 if (flags & PLANAR_FORMAT_HEADER_NA)
1802 context->AllowSkipAlpha = TRUE;
1804 if (flags & PLANAR_FORMAT_HEADER_RLE)
1805 context->AllowRunLengthEncoding = TRUE;
1807 if (flags & PLANAR_FORMAT_HEADER_CS)
1808 context->AllowColorSubsampling = TRUE;
1810 context->ColorLossLevel = flags & PLANAR_FORMAT_HEADER_CLL_MASK;
1812 if (context->ColorLossLevel)
1813 context->AllowDynamicColorFidelity = TRUE;
1815 if (!freerdp_bitmap_planar_context_reset(context, maxWidth, maxHeight))
1817 WINPR_PRAGMA_DIAG_PUSH
1818 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1819 freerdp_bitmap_planar_context_free(context);
1820 WINPR_PRAGMA_DIAG_POP
1827void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context)
1832 winpr_aligned_free(context->pTempData);
1833 winpr_aligned_free(context->planesBuffer);
1834 winpr_aligned_free(context->deltaPlanesBuffer);
1835 winpr_aligned_free(context->rlePlanesBuffer);
1836 winpr_aligned_free(context);
1839void freerdp_planar_switch_bgr(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL bgr)
1841 WINPR_ASSERT(planar);
1845void freerdp_planar_topdown_image(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL topdown)
1847 WINPR_ASSERT(planar);
1848 planar->topdown = topdown;