22 #include <freerdp/config.h>
24 #include <winpr/crt.h>
25 #include <winpr/wtypes.h>
26 #include <winpr/assert.h>
27 #include <winpr/print.h>
29 #include <freerdp/primitives.h>
30 #include <freerdp/log.h>
31 #include <freerdp/codec/bitmap.h>
32 #include <freerdp/codec/planar.h>
34 #define TAG FREERDP_TAG("codec")
36 #define PLANAR_ALIGN(val, align) \
37 ((val) % (align) == 0) ? (val) : ((val) + (align) - (val) % (align))
53 RDP6_RLE_SEGMENT* segments;
69 struct S_BITMAP_PLANAR_CONTEXT
76 BOOL AllowRunLengthEncoding;
77 BOOL AllowColorSubsampling;
78 BOOL AllowDynamicColorFidelity;
80 UINT32 ColorLossLevel;
86 BYTE* deltaPlanesBuffer;
89 BYTE* rlePlanesBuffer;
98 static INLINE UINT32 planar_invert_format(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL alpha,
102 if (planar->bgr && alpha)
106 case PIXEL_FORMAT_ARGB32:
107 DstFormat = PIXEL_FORMAT_ABGR32;
109 case PIXEL_FORMAT_XRGB32:
110 DstFormat = PIXEL_FORMAT_XBGR32;
112 case PIXEL_FORMAT_ABGR32:
113 DstFormat = PIXEL_FORMAT_ARGB32;
115 case PIXEL_FORMAT_XBGR32:
116 DstFormat = PIXEL_FORMAT_XRGB32;
118 case PIXEL_FORMAT_BGRA32:
119 DstFormat = PIXEL_FORMAT_RGBA32;
121 case PIXEL_FORMAT_BGRX32:
122 DstFormat = PIXEL_FORMAT_RGBX32;
124 case PIXEL_FORMAT_RGBA32:
125 DstFormat = PIXEL_FORMAT_BGRA32;
127 case PIXEL_FORMAT_RGBX32:
128 DstFormat = PIXEL_FORMAT_BGRX32;
130 case PIXEL_FORMAT_RGB24:
131 DstFormat = PIXEL_FORMAT_BGR24;
133 case PIXEL_FORMAT_BGR24:
134 DstFormat = PIXEL_FORMAT_RGB24;
136 case PIXEL_FORMAT_RGB16:
137 DstFormat = PIXEL_FORMAT_BGR16;
139 case PIXEL_FORMAT_BGR16:
140 DstFormat = PIXEL_FORMAT_RGB16;
142 case PIXEL_FORMAT_ARGB15:
143 DstFormat = PIXEL_FORMAT_ABGR15;
145 case PIXEL_FORMAT_RGB15:
146 DstFormat = PIXEL_FORMAT_BGR15;
148 case PIXEL_FORMAT_ABGR15:
149 DstFormat = PIXEL_FORMAT_ARGB15;
151 case PIXEL_FORMAT_BGR15:
152 DstFormat = PIXEL_FORMAT_RGB15;
161 static INLINE BOOL freerdp_bitmap_planar_compress_plane_rle(
const BYTE* WINPR_RESTRICT inPlane,
162 UINT32 width, UINT32 height,
163 BYTE* WINPR_RESTRICT outPlane,
164 UINT32* WINPR_RESTRICT dstSize);
165 static INLINE BYTE* freerdp_bitmap_planar_delta_encode_plane(
const BYTE* WINPR_RESTRICT inPlane,
166 UINT32 width, UINT32 height,
167 BYTE* WINPR_RESTRICT outPlane);
169 static INLINE INT32 planar_skip_plane_rle(
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
170 UINT32 nWidth, UINT32 nHeight)
173 BYTE controlByte = 0;
175 WINPR_ASSERT(pSrcData);
177 for (UINT32 y = 0; y < nHeight; y++)
179 for (UINT32 x = 0; x < nWidth;)
186 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used,
191 controlByte = pSrcData[used++];
192 nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
193 cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
197 nRunLength = cRawBytes + 16;
200 else if (nRunLength == 2)
202 nRunLength = cRawBytes + 32;
212 WLog_ERR(TAG,
"planar plane x %" PRIu32
" exceeds width %" PRIu32, x, nWidth);
218 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used,
225 if (used > INT32_MAX)
227 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used, SrcSize);
233 static INLINE INT32 planar_decompress_plane_rle_only(
const BYTE* WINPR_RESTRICT pSrcData,
234 UINT32 SrcSize, BYTE* WINPR_RESTRICT pDstData,
235 UINT32 nWidth, UINT32 nHeight)
238 UINT32 cRawBytes = 0;
239 UINT32 nRunLength = 0;
240 INT32 deltaValue = 0;
241 BYTE controlByte = 0;
242 BYTE* currentScanline = NULL;
243 BYTE* previousScanline = NULL;
244 const BYTE* srcp = pSrcData;
246 WINPR_ASSERT(nHeight <= INT32_MAX);
247 WINPR_ASSERT(nWidth <= INT32_MAX);
249 previousScanline = NULL;
251 for (INT32 y = 0; y < (INT32)nHeight; y++)
253 BYTE* dstp = &pDstData[(1ULL * (y) * (INT32)nWidth)];
255 currentScanline = dstp;
257 for (INT32 x = 0; x < (INT32)nWidth;)
262 if ((srcp - pSrcData) > SrcSize * 1ll)
264 WLog_ERR(TAG,
"error reading input buffer");
268 nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
269 cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
273 nRunLength = cRawBytes + 16;
276 else if (nRunLength == 2)
278 nRunLength = cRawBytes + 32;
282 if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 1ll)
284 WLog_ERR(TAG,
"too many pixels in scanline");
288 if (!previousScanline)
291 while (cRawBytes > 0)
301 while (nRunLength > 0)
312 while (cRawBytes > 0)
319 deltaValue = deltaValue >> 1;
320 deltaValue = deltaValue + 1;
325 deltaValue = deltaValue >> 1;
329 deltaValue = previousScanline[x] + pixel;
336 while (nRunLength > 0)
338 deltaValue = previousScanline[x] + pixel;
347 previousScanline = currentScanline;
350 return (INT32)(srcp - pSrcData);
353 static INLINE INT32 planar_decompress_plane_rle(
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
354 BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
355 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
356 UINT32 nHeight, UINT32 nChannel, BOOL vFlip)
359 UINT32 cRawBytes = 0;
360 UINT32 nRunLength = 0;
361 INT32 deltaValue = 0;
365 BYTE controlByte = 0;
366 BYTE* currentScanline = NULL;
367 BYTE* previousScanline = NULL;
368 const BYTE* srcp = pSrcData;
370 WINPR_ASSERT(nHeight <= INT32_MAX);
371 WINPR_ASSERT(nWidth <= INT32_MAX);
372 WINPR_ASSERT(nDstStep <= INT32_MAX);
374 previousScanline = NULL;
378 beg = (INT32)nHeight - 1;
385 end = (INT32)nHeight;
389 for (INT32 y = beg; y != end; y += inc)
391 BYTE* dstp = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4) + nChannel];
393 currentScanline = dstp;
395 for (INT32 x = 0; x < (INT32)nWidth;)
400 if ((srcp - pSrcData) > SrcSize * 1ll)
402 WLog_ERR(TAG,
"error reading input buffer");
406 nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
407 cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
411 nRunLength = cRawBytes + 16;
414 else if (nRunLength == 2)
416 nRunLength = cRawBytes + 32;
420 if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 4ll)
422 WLog_ERR(TAG,
"too many pixels in scanline");
426 if (!previousScanline)
429 while (cRawBytes > 0)
439 while (nRunLength > 0)
450 while (cRawBytes > 0)
457 deltaValue = deltaValue >> 1;
458 deltaValue = deltaValue + 1;
463 deltaValue = deltaValue >> 1;
467 deltaValue = previousScanline[4LL * x] + pixel;
474 while (nRunLength > 0)
476 deltaValue = previousScanline[4LL * x] + pixel;
485 previousScanline = currentScanline;
488 return (INT32)(srcp - pSrcData);
491 static INLINE INT32 planar_set_plane(BYTE bValue, BYTE* pDstData, UINT32 nDstStep, UINT32 nXDst,
492 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 nChannel,
499 WINPR_ASSERT(nHeight <= INT32_MAX);
500 WINPR_ASSERT(nWidth <= INT32_MAX);
501 WINPR_ASSERT(nDstStep <= INT32_MAX);
505 beg = (INT32)nHeight - 1;
512 end = (INT32)nHeight;
516 for (INT32 y = beg; y != end; y += inc)
518 BYTE* dstp = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4) + nChannel];
520 for (INT32 x = 0; x < (INT32)nWidth; ++x)
530 static INLINE BOOL writeLine(BYTE** WINPR_RESTRICT ppRgba, UINT32 DstFormat, UINT32 width,
531 const BYTE** WINPR_RESTRICT ppR,
const BYTE** WINPR_RESTRICT ppG,
532 const BYTE** WINPR_RESTRICT ppB,
const BYTE** WINPR_RESTRICT ppA)
534 WINPR_ASSERT(ppRgba);
541 case PIXEL_FORMAT_BGRA32:
542 for (UINT32 x = 0; x < width; x++)
544 *(*ppRgba)++ = *(*ppB)++;
545 *(*ppRgba)++ = *(*ppG)++;
546 *(*ppRgba)++ = *(*ppR)++;
547 *(*ppRgba)++ = *(*ppA)++;
552 case PIXEL_FORMAT_BGRX32:
553 for (UINT32 x = 0; x < width; x++)
555 *(*ppRgba)++ = *(*ppB)++;
556 *(*ppRgba)++ = *(*ppG)++;
557 *(*ppRgba)++ = *(*ppR)++;
566 for (UINT32 x = 0; x < width; x++)
568 BYTE alpha = *(*ppA)++;
570 FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
571 FreeRDPWriteColor(*ppRgba, DstFormat, color);
572 *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
577 const BYTE alpha = 0xFF;
579 for (UINT32 x = 0; x < width; x++)
582 FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
583 FreeRDPWriteColor(*ppRgba, DstFormat, color);
584 *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
592 static INLINE BOOL planar_decompress_planes_raw(
const BYTE* WINPR_RESTRICT pSrcData[4],
593 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
594 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
595 UINT32 nWidth, UINT32 nHeight, BOOL vFlip,
601 const BYTE* pR = pSrcData[0];
602 const BYTE* pG = pSrcData[1];
603 const BYTE* pB = pSrcData[2];
604 const BYTE* pA = pSrcData[3];
605 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
620 if (nYDst + nHeight > totalHeight)
623 "planar plane destination Y %" PRIu32
" + height %" PRIu32
624 " exceeds totalHeight %" PRIu32,
625 nYDst, nHeight, totalHeight);
629 if ((nXDst + nWidth) * bpp > nDstStep)
632 "planar plane destination (X %" PRIu32
" + width %" PRIu32
") * bpp %" PRIu32
633 " exceeds stride %" PRIu32,
634 nXDst, nWidth, bpp, nDstStep);
638 for (INT32 y = beg; y != end; y += inc)
642 if (y > (INT64)nHeight)
644 WLog_ERR(TAG,
"planar plane destination Y %" PRId32
" exceeds height %" PRIu32, y,
649 pRGB = &pDstData[((nYDst + y) * nDstStep) + (nXDst * bpp)];
651 if (!writeLine(&pRGB, DstFormat, nWidth, &pR, &pG, &pB, &pA))
658 static BOOL planar_subsample_expand(
const BYTE* WINPR_RESTRICT plane,
size_t planeLength,
659 UINT32 nWidth, UINT32 nHeight, UINT32 nPlaneWidth,
660 UINT32 nPlaneHeight, BYTE* WINPR_RESTRICT deltaPlane)
663 WINPR_UNUSED(planeLength);
666 WINPR_ASSERT(deltaPlane);
668 if (nWidth > nPlaneWidth * 2)
670 WLog_ERR(TAG,
"planar subsample width %" PRIu32
" > PlaneWidth %" PRIu32
" * 2", nWidth,
675 if (nHeight > nPlaneHeight * 2)
677 WLog_ERR(TAG,
"planar subsample height %" PRIu32
" > PlaneHeight %" PRIu32
" * 2", nHeight,
682 for (
size_t y = 0; y < nHeight; y++)
684 const BYTE* src = plane + y / 2 * nPlaneWidth;
686 for (UINT32 x = 0; x < nWidth; x++)
688 deltaPlane[pos++] = src[x / 2];
695 BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
696 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 nSrcWidth,
697 UINT32 nSrcHeight, BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
698 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
699 UINT32 nDstHeight, BOOL vFlip)
705 BOOL useAlpha = FALSE;
707 const BYTE* srcp = NULL;
710 UINT32 subHeight = 0;
711 UINT32 planeSize = 0;
712 INT32 rleSizes[4] = { 0, 0, 0, 0 };
715 UINT32 rawHeights[4];
716 BYTE FormatHeader = 0;
717 const BYTE* planes[4] = { 0 };
718 const UINT32 w = MIN(nSrcWidth, nDstWidth);
719 const UINT32 h = MIN(nSrcHeight, nDstHeight);
722 WINPR_ASSERT(planar);
726 nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat);
732 WLog_ERR(TAG,
"Invalid argument pSrcData=NULL");
738 WLog_ERR(TAG,
"Invalid argument pDstData=NULL");
742 FormatHeader = *srcp++;
743 cll = (FormatHeader & PLANAR_FORMAT_HEADER_CLL_MASK);
744 cs = (FormatHeader & PLANAR_FORMAT_HEADER_CS) ? TRUE : FALSE;
745 rle = (FormatHeader & PLANAR_FORMAT_HEADER_RLE) ? TRUE : FALSE;
746 alpha = (FormatHeader & PLANAR_FORMAT_HEADER_NA) ? FALSE : TRUE;
748 DstFormat = planar_invert_format(planar, alpha, DstFormat);
751 useAlpha = FreeRDPColorHasAlpha(DstFormat);
758 WLog_ERR(TAG,
"Chroma subsampling requires YCoCg and does not work with RGB data");
762 subWidth = (nSrcWidth / 2) + (nSrcWidth % 2);
763 subHeight = (nSrcHeight / 2) + (nSrcHeight % 2);
764 planeSize = nSrcWidth * nSrcHeight;
765 subSize = subWidth * subHeight;
769 rawSizes[0] = planeSize;
770 rawWidths[0] = nSrcWidth;
771 rawHeights[0] = nSrcHeight;
772 rawSizes[1] = planeSize;
773 rawWidths[1] = nSrcWidth;
774 rawHeights[1] = nSrcHeight;
775 rawSizes[2] = planeSize;
776 rawWidths[2] = nSrcWidth;
777 rawHeights[2] = nSrcHeight;
778 rawSizes[3] = planeSize;
779 rawWidths[3] = nSrcWidth;
780 rawHeights[3] = nSrcHeight;
784 rawSizes[0] = planeSize;
785 rawWidths[0] = nSrcWidth;
786 rawHeights[0] = nSrcHeight;
787 rawSizes[1] = subSize;
788 rawWidths[1] = subWidth;
789 rawHeights[1] = subHeight;
790 rawSizes[2] = subSize;
791 rawWidths[2] = subWidth;
792 rawHeights[2] = subHeight;
793 rawSizes[3] = planeSize;
794 rawWidths[3] = nSrcWidth;
795 rawHeights[3] = nSrcHeight;
798 const size_t diff = srcp - pSrcData;
801 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
808 UINT32 base = planeSize * 3;
810 base = planeSize + planeSize / 2;
814 if ((SrcSize - diff) < (planeSize + base))
816 WLog_ERR(TAG,
"Alpha plane size mismatch %" PRIuz
" < %" PRIu32, SrcSize - diff,
822 planes[0] = planes[3] + rawSizes[3];
823 planes[1] = planes[0] + rawSizes[0];
824 planes[2] = planes[1] + rawSizes[1];
826 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
828 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p", planes[2], rawSizes[2],
835 if ((SrcSize - diff) < base)
837 WLog_ERR(TAG,
"plane size mismatch %" PRIu32
" < %" PRIu32, SrcSize - diff, base);
842 planes[1] = planes[0] + rawSizes[0];
843 planes[2] = planes[1] + rawSizes[1];
845 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
847 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p", planes[2], rawSizes[2],
858 rleSizes[3] = planar_skip_plane_rle(planes[3], (UINT32)(SrcSize - diff), rawWidths[3],
864 planes[0] = planes[3] + rleSizes[3];
869 const size_t diff0 = (planes[0] - pSrcData);
872 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff0);
875 rleSizes[0] = planar_skip_plane_rle(planes[0], (UINT32)(SrcSize - diff0), rawWidths[0],
881 planes[1] = planes[0] + rleSizes[0];
883 const size_t diff1 = (planes[1] - pSrcData);
886 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff1);
889 rleSizes[1] = planar_skip_plane_rle(planes[1], (UINT32)(SrcSize - diff1), rawWidths[1],
895 planes[2] = planes[1] + rleSizes[1];
896 const size_t diff2 = (planes[2] - pSrcData);
899 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
902 rleSizes[2] = planar_skip_plane_rle(planes[2], (UINT32)(SrcSize - diff2), rawWidths[2],
911 UINT32 TempFormat = 0;
912 BYTE* pTempData = pDstData;
913 UINT32 nTempStep = nDstStep;
914 UINT32 nTotalHeight = nYDst + nDstHeight;
917 TempFormat = PIXEL_FORMAT_BGRA32;
919 TempFormat = PIXEL_FORMAT_BGRX32;
921 TempFormat = planar_invert_format(planar, alpha, TempFormat);
923 if ((TempFormat != DstFormat) || (nSrcWidth != nDstWidth) || (nSrcHeight != nDstHeight))
925 pTempData = planar->pTempData;
926 nTempStep = planar->nTempStep;
927 nTotalHeight = planar->maxHeight;
932 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
933 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
937 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
939 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
941 if ((SrcSize - (srcp - pSrcData)) == 1)
947 planar_decompress_plane_rle(planes[0], rleSizes[0], pTempData, nTempStep, nXDst,
948 nYDst, nSrcWidth, nSrcHeight, 2, vFlip);
953 status = planar_decompress_plane_rle(planes[1], rleSizes[1], pTempData, nTempStep,
954 nXDst, nYDst, nSrcWidth, nSrcHeight, 1,
961 planar_decompress_plane_rle(planes[2], rleSizes[2], pTempData, nTempStep, nXDst,
962 nYDst, nSrcWidth, nSrcHeight, 0, vFlip);
967 srcp += rleSizes[0] + rleSizes[1] + rleSizes[2];
971 status = planar_decompress_plane_rle(planes[3], rleSizes[3], pTempData, nTempStep,
972 nXDst, nYDst, nSrcWidth, nSrcHeight, 3,
976 status = planar_set_plane(0xFF, pTempData, nTempStep, nXDst, nYDst, nSrcWidth,
977 nSrcHeight, 3, vFlip);
986 if (pTempData != pDstData)
988 if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, w, h,
989 pTempData, TempFormat, nTempStep, nXDst, nYDst, NULL,
992 WLog_ERR(TAG,
"planar image copy failed");
999 UINT32 TempFormat = 0;
1000 BYTE* pTempData = planar->pTempData;
1001 UINT32 nTempStep = planar->nTempStep;
1002 UINT32 nTotalHeight = planar->maxHeight;
1003 BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
1006 TempFormat = PIXEL_FORMAT_BGRA32;
1008 TempFormat = PIXEL_FORMAT_BGRX32;
1015 BYTE* rleBuffer[4] = { 0 };
1017 if (!planar->rlePlanesBuffer)
1020 rleBuffer[3] = planar->rlePlanesBuffer;
1021 rleBuffer[0] = rleBuffer[3] + planeSize;
1022 rleBuffer[1] = rleBuffer[0] + planeSize;
1023 rleBuffer[2] = rleBuffer[1] + planeSize;
1027 planar_decompress_plane_rle_only(planes[3], rleSizes[3], rleBuffer[3],
1028 rawWidths[3], rawHeights[3]);
1035 srcp += rleSizes[3];
1037 status = planar_decompress_plane_rle_only(planes[0], rleSizes[0], rleBuffer[0],
1038 rawWidths[0], rawHeights[0]);
1044 planar_decompress_plane_rle_only(planes[1], rleSizes[1], rleBuffer[1], rawWidths[1],
1051 planar_decompress_plane_rle_only(planes[2], rleSizes[2], rleBuffer[2], rawWidths[2],
1057 planes[0] = rleBuffer[0];
1058 planes[1] = rleBuffer[1];
1059 planes[2] = rleBuffer[2];
1060 planes[3] = rleBuffer[3];
1069 if (!planar_subsample_expand(planes[1], rawSizes[1], nSrcWidth, nSrcHeight,
1070 rawWidths[1], rawHeights[1], planar->deltaPlanes[0]))
1073 planes[1] = planar->deltaPlanes[0];
1074 rawSizes[1] = planeSize;
1075 rawWidths[1] = nSrcWidth;
1076 rawHeights[1] = nSrcHeight;
1078 if (!planar_subsample_expand(planes[2], rawSizes[2], nSrcWidth, nSrcHeight,
1079 rawWidths[2], rawHeights[2], planar->deltaPlanes[1]))
1082 planes[2] = planar->deltaPlanes[1];
1083 rawSizes[2] = planeSize;
1084 rawWidths[2] = nSrcWidth;
1085 rawHeights[2] = nSrcHeight;
1088 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
1089 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
1093 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
1095 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
1097 if ((SrcSize - (srcp - pSrcData)) == 1)
1101 WINPR_ASSERT(prims->YCoCgToRGB_8u_AC4R);
1102 int rc = prims->YCoCgToRGB_8u_AC4R(pTempData, nTempStep, dst, DstFormat, nDstStep, w, h,
1104 if (rc != PRIMITIVES_SUCCESS)
1106 WLog_ERR(TAG,
"YCoCgToRGB_8u_AC4R failed with %d", rc);
1115 static INLINE BOOL freerdp_split_color_planes(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
1116 const BYTE* WINPR_RESTRICT data, UINT32 format,
1117 UINT32 width, UINT32 height, UINT32 scanline,
1118 BYTE* WINPR_RESTRICT planes[4])
1120 WINPR_ASSERT(planar);
1122 if ((width > INT32_MAX) || (height > INT32_MAX) || (scanline > INT32_MAX))
1126 scanline = width * FreeRDPGetBytesPerPixel(format);
1128 if (planar->topdown)
1131 for (UINT32 i = 0; i < height; i++)
1133 const BYTE* pixel = &data[1ULL * scanline * i];
1135 for (UINT32 j = 0; j < width; j++)
1137 const UINT32 color = FreeRDPReadColor(pixel, format);
1138 pixel += FreeRDPGetBytesPerPixel(format);
1139 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1140 &planes[0][k], NULL);
1149 for (INT64 i = (INT64)height - 1; i >= 0; i--)
1151 const BYTE* pixel = &data[1ULL * scanline * (UINT32)i];
1153 for (UINT32 j = 0; j < width; j++)
1155 const UINT32 color = FreeRDPReadColor(pixel, format);
1156 pixel += FreeRDPGetBytesPerPixel(format);
1157 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1158 &planes[0][k], NULL);
1166 static INLINE UINT32 freerdp_bitmap_planar_write_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1167 UINT32 cRawBytes, UINT32 nRunLength,
1168 BYTE* WINPR_RESTRICT pOutBuffer,
1169 UINT32 outBufferSize)
1171 const BYTE* pInput = NULL;
1172 BYTE* pOutput = NULL;
1173 BYTE controlByte = 0;
1174 UINT32 nBytesToWrite = 0;
1176 pOutput = pOutBuffer;
1178 if (!cRawBytes && !nRunLength)
1183 cRawBytes += nRunLength;
1191 if (nRunLength > 15)
1193 if (nRunLength < 18)
1195 controlByte = PLANAR_CONTROL_BYTE(13, cRawBytes);
1201 controlByte = PLANAR_CONTROL_BYTE(15, cRawBytes);
1208 controlByte = PLANAR_CONTROL_BYTE(nRunLength, cRawBytes);
1215 controlByte = PLANAR_CONTROL_BYTE(0, 15);
1219 if (outBufferSize < 1)
1223 *pOutput = controlByte;
1225 nBytesToWrite = (controlByte >> 4);
1229 if (outBufferSize < nBytesToWrite)
1232 outBufferSize -= nBytesToWrite;
1233 CopyMemory(pOutput, pInput, nBytesToWrite);
1234 pOutput += nBytesToWrite;
1235 pInput += nBytesToWrite;
1241 if (nRunLength > 47)
1243 if (nRunLength < 50)
1245 controlByte = PLANAR_CONTROL_BYTE(2, 13);
1250 controlByte = PLANAR_CONTROL_BYTE(2, 15);
1254 else if (nRunLength > 31)
1256 controlByte = PLANAR_CONTROL_BYTE(2, (nRunLength - 32));
1259 else if (nRunLength > 15)
1261 controlByte = PLANAR_CONTROL_BYTE(1, (nRunLength - 16));
1266 controlByte = PLANAR_CONTROL_BYTE(nRunLength, 0);
1270 if (outBufferSize < 1)
1274 *pOutput = controlByte;
1278 const intptr_t diff = (pOutput - pOutBuffer);
1279 if ((diff < 0) || (diff > UINT32_MAX))
1281 return (UINT32)diff;
1284 static INLINE UINT32 freerdp_bitmap_planar_encode_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1285 UINT32 inBufferSize,
1286 BYTE* WINPR_RESTRICT pOutBuffer,
1287 UINT32 outBufferSize)
1290 const BYTE* pInput = NULL;
1291 BYTE* pOutput = NULL;
1292 const BYTE* pBytes = NULL;
1293 UINT32 cRawBytes = 0;
1294 UINT32 nRunLength = 0;
1295 UINT32 bSymbolMatch = 0;
1296 UINT32 nBytesWritten = 0;
1297 UINT32 nTotalBytesWritten = 0;
1302 pOutput = pOutBuffer;
1303 nTotalBytesWritten = 0;
1313 bSymbolMatch = (symbol == *pInput) ? TRUE : FALSE;
1318 if (nRunLength && !bSymbolMatch)
1322 cRawBytes += nRunLength;
1327 pBytes = pInput - (cRawBytes + nRunLength + 1);
1328 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1329 pOutput, outBufferSize);
1332 if (!nBytesWritten || (nBytesWritten > outBufferSize))
1335 nTotalBytesWritten += nBytesWritten;
1336 outBufferSize -= nBytesWritten;
1337 pOutput += nBytesWritten;
1342 nRunLength += bSymbolMatch;
1343 cRawBytes += (!bSymbolMatch) ? TRUE : FALSE;
1344 }
while (outBufferSize);
1346 if (cRawBytes || nRunLength)
1348 pBytes = pInput - (cRawBytes + nRunLength);
1349 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1350 pOutput, outBufferSize);
1355 nTotalBytesWritten += nBytesWritten;
1361 return nTotalBytesWritten;
1364 BOOL freerdp_bitmap_planar_compress_plane_rle(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1365 UINT32 height, BYTE* WINPR_RESTRICT outPlane,
1366 UINT32* WINPR_RESTRICT dstSize)
1369 const BYTE* pInput = NULL;
1370 BYTE* pOutput = NULL;
1371 UINT32 outBufferSize = 0;
1372 UINT32 nBytesWritten = 0;
1373 UINT32 nTotalBytesWritten = 0;
1381 outBufferSize = *dstSize;
1382 nTotalBytesWritten = 0;
1384 while (outBufferSize)
1387 freerdp_bitmap_planar_encode_rle_bytes(pInput, width, pOutput, outBufferSize);
1389 if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
1392 outBufferSize -= nBytesWritten;
1393 nTotalBytesWritten += nBytesWritten;
1394 pOutput += nBytesWritten;
1398 if (index >= height)
1402 *dstSize = nTotalBytesWritten;
1406 static INLINE BOOL freerdp_bitmap_planar_compress_planes_rle(BYTE* WINPR_RESTRICT inPlanes[4],
1407 UINT32 width, UINT32 height,
1408 BYTE* WINPR_RESTRICT outPlanes,
1409 UINT32* WINPR_RESTRICT dstSizes,
1412 UINT32 outPlanesSize = width * height * 4;
1421 dstSizes[0] = outPlanesSize;
1423 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[0], width, height, outPlanes,
1427 outPlanes += dstSizes[0];
1428 outPlanesSize -= dstSizes[0];
1432 dstSizes[1] = outPlanesSize;
1434 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[1], width, height, outPlanes,
1438 outPlanes += dstSizes[1];
1439 outPlanesSize -= dstSizes[1];
1441 dstSizes[2] = outPlanesSize;
1443 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[2], width, height, outPlanes,
1447 outPlanes += dstSizes[2];
1448 outPlanesSize -= dstSizes[2];
1450 dstSizes[3] = outPlanesSize;
1452 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[3], width, height, outPlanes,
1459 BYTE* freerdp_bitmap_planar_delta_encode_plane(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1460 UINT32 height, BYTE* WINPR_RESTRICT outPlane)
1463 BYTE* outPtr = NULL;
1464 const BYTE* srcPtr = NULL;
1465 const BYTE* prevLinePtr = NULL;
1469 if (width * height == 0)
1472 if (!(outPlane = (BYTE*)calloc(height, width)))
1477 CopyMemory(outPlane, inPlane, width);
1478 outPtr = outPlane + width;
1479 srcPtr = inPlane + width;
1480 prevLinePtr = inPlane;
1482 for (UINT32 y = 1; y < height; y++)
1484 for (UINT32 x = 0; x < width; x++, outPtr++, srcPtr++, prevLinePtr++)
1486 INT32 delta = *srcPtr - *prevLinePtr;
1487 s2c = (delta >= 0) ? (
char)delta : (char)(~((BYTE)(-delta)) + 1);
1488 s2c = (s2c >= 0) ? (
char)((UINT32)s2c << 1)
1489 : (char)(((UINT32)(~((BYTE)s2c) + 1) << 1) - 1);
1490 *outPtr = (BYTE)s2c;
1497 static INLINE BOOL freerdp_bitmap_planar_delta_encode_planes(BYTE* WINPR_RESTRICT inPlanes[4],
1498 UINT32 width, UINT32 height,
1499 BYTE* WINPR_RESTRICT outPlanes[4])
1501 for (UINT32 i = 0; i < 4; i++)
1504 freerdp_bitmap_planar_delta_encode_plane(inPlanes[i], width, height, outPlanes[i]);
1513 BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1514 const BYTE* WINPR_RESTRICT data, UINT32 format, UINT32 width,
1515 UINT32 height, UINT32 scanline, BYTE* WINPR_RESTRICT dstData,
1516 UINT32* WINPR_RESTRICT pDstSize)
1520 UINT32 planeSize = 0;
1521 UINT32 dstSizes[4] = { 0 };
1522 BYTE FormatHeader = 0;
1524 if (!context || !context->rlePlanesBuffer)
1527 if (context->AllowSkipAlpha)
1528 FormatHeader |= PLANAR_FORMAT_HEADER_NA;
1530 planeSize = width * height;
1532 if (!context->AllowSkipAlpha)
1533 format = planar_invert_format(context, TRUE, format);
1535 if (!freerdp_split_color_planes(context, data, format, width, height, scanline,
1539 if (context->AllowRunLengthEncoding)
1541 if (!freerdp_bitmap_planar_delta_encode_planes(context->planes, width, height,
1542 context->deltaPlanes))
1545 if (!freerdp_bitmap_planar_compress_planes_rle(context->deltaPlanes, width, height,
1546 context->rlePlanesBuffer, dstSizes,
1547 context->AllowSkipAlpha))
1552 FormatHeader |= PLANAR_FORMAT_HEADER_RLE;
1553 context->rlePlanes[0] = &context->rlePlanesBuffer[offset];
1554 offset += dstSizes[0];
1555 context->rlePlanes[1] = &context->rlePlanesBuffer[offset];
1556 offset += dstSizes[1];
1557 context->rlePlanes[2] = &context->rlePlanesBuffer[offset];
1558 offset += dstSizes[2];
1559 context->rlePlanes[3] = &context->rlePlanesBuffer[offset];
1561 #if defined(WITH_DEBUG_CODECS)
1563 "R: [%" PRIu32
"/%" PRIu32
"] G: [%" PRIu32
"/%" PRIu32
"] B: [%" PRIu32
1565 dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize);
1570 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1572 if (!context->AllowRunLengthEncoding)
1575 if (context->rlePlanes[0] == NULL)
1578 if (context->rlePlanes[1] == NULL)
1581 if (context->rlePlanes[2] == NULL)
1584 if (context->rlePlanes[3] == NULL)
1592 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1594 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1595 size += dstSizes[0];
1600 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1601 size += (dstSizes[1] + dstSizes[2] + dstSizes[3]);
1603 size += (planeSize * 3);
1605 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1608 dstData = malloc(size);
1617 *dstp = FormatHeader;
1622 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1624 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1626 CopyMemory(dstp, context->rlePlanes[0], dstSizes[0]);
1627 dstp += dstSizes[0];
1631 CopyMemory(dstp, context->planes[0], planeSize);
1638 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1640 CopyMemory(dstp, context->rlePlanes[1], dstSizes[1]);
1641 dstp += dstSizes[1];
1645 CopyMemory(dstp, context->planes[1], planeSize);
1651 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1653 CopyMemory(dstp, context->rlePlanes[2], dstSizes[2]);
1654 dstp += dstSizes[2];
1658 CopyMemory(dstp, context->planes[2], planeSize);
1664 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1666 CopyMemory(dstp, context->rlePlanes[3], dstSizes[3]);
1667 dstp += dstSizes[3];
1671 CopyMemory(dstp, context->planes[3], planeSize);
1677 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1683 const intptr_t diff = (dstp - dstData);
1684 if ((diff < 0) || (diff > UINT32_MAX))
1689 size = (UINT32)diff;
1694 BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1695 UINT32 width, UINT32 height)
1700 context->bgr = FALSE;
1701 context->maxWidth = PLANAR_ALIGN(width, 4);
1702 context->maxHeight = PLANAR_ALIGN(height, 4);
1704 const UINT64 tmp = (UINT64)context->maxWidth * context->maxHeight;
1705 if (tmp > UINT32_MAX)
1707 context->maxPlaneSize = (UINT32)tmp;
1710 if (context->maxWidth > UINT32_MAX / 4)
1712 context->nTempStep = context->maxWidth * 4;
1714 memset(context->planes, 0,
sizeof(context->planes));
1715 memset(context->rlePlanes, 0,
sizeof(context->rlePlanes));
1716 memset(context->deltaPlanes, 0,
sizeof(context->deltaPlanes));
1718 if (context->maxPlaneSize > 0)
1720 void* tmp = winpr_aligned_recalloc(context->planesBuffer, context->maxPlaneSize, 4, 32);
1723 context->planesBuffer = tmp;
1725 tmp = winpr_aligned_recalloc(context->pTempData, context->maxPlaneSize, 6, 32);
1728 context->pTempData = tmp;
1730 tmp = winpr_aligned_recalloc(context->deltaPlanesBuffer, context->maxPlaneSize, 4, 32);
1733 context->deltaPlanesBuffer = tmp;
1735 tmp = winpr_aligned_recalloc(context->rlePlanesBuffer, context->maxPlaneSize, 4, 32);
1738 context->rlePlanesBuffer = tmp;
1740 context->planes[0] = &context->planesBuffer[0ULL * context->maxPlaneSize];
1741 context->planes[1] = &context->planesBuffer[1ULL * context->maxPlaneSize];
1742 context->planes[2] = &context->planesBuffer[2ULL * context->maxPlaneSize];
1743 context->planes[3] = &context->planesBuffer[3ULL * context->maxPlaneSize];
1744 context->deltaPlanes[0] = &context->deltaPlanesBuffer[0ULL * context->maxPlaneSize];
1745 context->deltaPlanes[1] = &context->deltaPlanesBuffer[1ULL * context->maxPlaneSize];
1746 context->deltaPlanes[2] = &context->deltaPlanesBuffer[2ULL * context->maxPlaneSize];
1747 context->deltaPlanes[3] = &context->deltaPlanesBuffer[3ULL * context->maxPlaneSize];
1752 BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, UINT32 maxWidth,
1755 BITMAP_PLANAR_CONTEXT* context =
1756 (BITMAP_PLANAR_CONTEXT*)winpr_aligned_calloc(1,
sizeof(BITMAP_PLANAR_CONTEXT), 32);
1761 if (flags & PLANAR_FORMAT_HEADER_NA)
1762 context->AllowSkipAlpha = TRUE;
1764 if (flags & PLANAR_FORMAT_HEADER_RLE)
1765 context->AllowRunLengthEncoding = TRUE;
1767 if (flags & PLANAR_FORMAT_HEADER_CS)
1768 context->AllowColorSubsampling = TRUE;
1770 context->ColorLossLevel = flags & PLANAR_FORMAT_HEADER_CLL_MASK;
1772 if (context->ColorLossLevel)
1773 context->AllowDynamicColorFidelity = TRUE;
1775 if (!freerdp_bitmap_planar_context_reset(context, maxWidth, maxHeight))
1777 WINPR_PRAGMA_DIAG_PUSH
1778 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1779 freerdp_bitmap_planar_context_free(context);
1780 WINPR_PRAGMA_DIAG_POP
1787 void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context)
1792 winpr_aligned_free(context->pTempData);
1793 winpr_aligned_free(context->planesBuffer);
1794 winpr_aligned_free(context->deltaPlanesBuffer);
1795 winpr_aligned_free(context->rlePlanesBuffer);
1796 winpr_aligned_free(context);
1799 void freerdp_planar_switch_bgr(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL bgr)
1801 WINPR_ASSERT(planar);
1805 void freerdp_planar_topdown_image(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL topdown)
1807 WINPR_ASSERT(planar);
1808 planar->topdown = topdown;