22 #include <freerdp/config.h>
24 #include <winpr/crt.h>
25 #include <winpr/wtypes.h>
26 #include <winpr/assert.h>
27 #include <winpr/cast.h>
28 #include <winpr/print.h>
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;
70 struct S_BITMAP_PLANAR_CONTEXT
77 BOOL AllowRunLengthEncoding;
78 BOOL AllowColorSubsampling;
79 BOOL AllowDynamicColorFidelity;
81 UINT32 ColorLossLevel;
87 BYTE* deltaPlanesBuffer;
90 BYTE* rlePlanesBuffer;
99 static INLINE UINT32 planar_invert_format(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL alpha,
103 if (planar->bgr && alpha)
107 case PIXEL_FORMAT_ARGB32:
108 DstFormat = PIXEL_FORMAT_ABGR32;
110 case PIXEL_FORMAT_XRGB32:
111 DstFormat = PIXEL_FORMAT_XBGR32;
113 case PIXEL_FORMAT_ABGR32:
114 DstFormat = PIXEL_FORMAT_ARGB32;
116 case PIXEL_FORMAT_XBGR32:
117 DstFormat = PIXEL_FORMAT_XRGB32;
119 case PIXEL_FORMAT_BGRA32:
120 DstFormat = PIXEL_FORMAT_RGBA32;
122 case PIXEL_FORMAT_BGRX32:
123 DstFormat = PIXEL_FORMAT_RGBX32;
125 case PIXEL_FORMAT_RGBA32:
126 DstFormat = PIXEL_FORMAT_BGRA32;
128 case PIXEL_FORMAT_RGBX32:
129 DstFormat = PIXEL_FORMAT_BGRX32;
131 case PIXEL_FORMAT_RGB24:
132 DstFormat = PIXEL_FORMAT_BGR24;
134 case PIXEL_FORMAT_BGR24:
135 DstFormat = PIXEL_FORMAT_RGB24;
137 case PIXEL_FORMAT_RGB16:
138 DstFormat = PIXEL_FORMAT_BGR16;
140 case PIXEL_FORMAT_BGR16:
141 DstFormat = PIXEL_FORMAT_RGB16;
143 case PIXEL_FORMAT_ARGB15:
144 DstFormat = PIXEL_FORMAT_ABGR15;
146 case PIXEL_FORMAT_RGB15:
147 DstFormat = PIXEL_FORMAT_BGR15;
149 case PIXEL_FORMAT_ABGR15:
150 DstFormat = PIXEL_FORMAT_ARGB15;
152 case PIXEL_FORMAT_BGR15:
153 DstFormat = PIXEL_FORMAT_RGB15;
162 static INLINE BOOL freerdp_bitmap_planar_compress_plane_rle(
const BYTE* WINPR_RESTRICT inPlane,
163 UINT32 width, UINT32 height,
164 BYTE* WINPR_RESTRICT outPlane,
165 UINT32* WINPR_RESTRICT dstSize);
166 static INLINE BYTE* freerdp_bitmap_planar_delta_encode_plane(
const BYTE* WINPR_RESTRICT inPlane,
167 UINT32 width, UINT32 height,
168 BYTE* WINPR_RESTRICT outPlane);
170 static INLINE INT32 planar_skip_plane_rle(
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
171 UINT32 nWidth, UINT32 nHeight)
175 WINPR_ASSERT(pSrcData);
177 for (UINT32 y = 0; y < nHeight; y++)
179 for (UINT32 x = 0; x < nWidth;)
183 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used,
188 const uint8_t controlByte = pSrcData[used++];
189 uint32_t nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
190 uint32_t cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
194 nRunLength = cRawBytes + 16;
197 else if (nRunLength == 2)
199 nRunLength = cRawBytes + 32;
209 WLog_ERR(TAG,
"planar plane x %" PRIu32
" exceeds width %" PRIu32, x, nWidth);
215 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used,
222 if (used > INT32_MAX)
224 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used, SrcSize);
230 static inline UINT8 clamp(INT16 val)
235 static INLINE INT32 planar_decompress_plane_rle_only(
const BYTE* WINPR_RESTRICT pSrcData,
236 UINT32 SrcSize, BYTE* WINPR_RESTRICT pDstData,
237 UINT32 nWidth, UINT32 nHeight)
239 BYTE* previousScanline = NULL;
240 const BYTE* srcp = pSrcData;
242 WINPR_ASSERT(nHeight <= INT32_MAX);
243 WINPR_ASSERT(nWidth <= INT32_MAX);
245 for (UINT32 y = 0; y < nHeight; y++)
247 BYTE* dstp = &pDstData[1ULL * (y)*nWidth];
249 BYTE* currentScanline = dstp;
251 for (UINT32 x = 0; x < nWidth;)
253 BYTE controlByte = *srcp;
256 if ((srcp - pSrcData) > SrcSize * 1ll)
258 WLog_ERR(TAG,
"error reading input buffer");
262 UINT32 nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
263 UINT32 cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
267 nRunLength = cRawBytes + 16;
270 else if (nRunLength == 2)
272 nRunLength = cRawBytes + 32;
276 if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 1ll)
278 WLog_ERR(TAG,
"too many pixels in scanline");
282 if (!previousScanline)
285 while (cRawBytes > 0)
295 while (nRunLength > 0)
307 while (cRawBytes > 0)
309 UINT8 deltaValue = *srcp;
314 deltaValue = deltaValue >> 1;
315 deltaValue = deltaValue + 1;
316 p = WINPR_ASSERTING_INT_CAST(int16_t, -1 * (int16_t)deltaValue);
320 deltaValue = deltaValue >> 1;
321 p = WINPR_ASSERTING_INT_CAST(INT16, deltaValue);
324 const INT16 delta = WINPR_ASSERTING_INT_CAST(int16_t, previousScanline[x] + p);
325 *dstp = clamp(delta);
331 while (nRunLength > 0)
333 const INT16 deltaValue =
334 WINPR_ASSERTING_INT_CAST(int16_t, previousScanline[x] + p);
335 *dstp = clamp(deltaValue);
343 previousScanline = currentScanline;
346 return (INT32)(srcp - pSrcData);
349 static INLINE INT32 planar_decompress_plane_rle(
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
350 BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
351 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
352 UINT32 nHeight, UINT32 nChannel, BOOL vFlip)
357 BYTE* previousScanline = NULL;
358 const BYTE* srcp = pSrcData;
360 WINPR_ASSERT(nHeight <= INT32_MAX);
361 WINPR_ASSERT(nWidth <= INT32_MAX);
362 WINPR_ASSERT(nDstStep <= INT32_MAX);
364 previousScanline = NULL;
368 beg = (INT32)nHeight - 1;
375 end = (INT32)nHeight;
379 for (INT32 y = beg; y != end; y += inc)
381 const intptr_t off = ((1LL * nYDst + y) * nDstStep) + (4LL * nXDst) + nChannel * 1LL;
382 BYTE* dstp = &pDstData[off];
383 BYTE* currentScanline = dstp;
386 for (INT32 x = 0; x < (INT32)nWidth;)
388 const BYTE controlByte = *srcp;
391 if ((srcp - pSrcData) > SrcSize * 1ll)
393 WLog_ERR(TAG,
"error reading input buffer");
397 UINT32 nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
398 UINT32 cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
402 nRunLength = cRawBytes + 16;
405 else if (nRunLength == 2)
407 nRunLength = cRawBytes + 32;
411 if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 4ll)
413 WLog_ERR(TAG,
"too many pixels in scanline");
417 if (!previousScanline)
420 while (cRawBytes > 0)
424 *dstp = WINPR_ASSERTING_INT_CAST(BYTE, pixel);
430 while (nRunLength > 0)
432 *dstp = WINPR_ASSERTING_INT_CAST(BYTE, pixel);
441 while (cRawBytes > 0)
443 BYTE deltaValue = *srcp;
448 deltaValue = deltaValue >> 1;
449 deltaValue = deltaValue + 1;
450 pixel = WINPR_ASSERTING_INT_CAST(int16_t, -deltaValue);
454 deltaValue = deltaValue >> 1;
459 WINPR_ASSERTING_INT_CAST(int16_t, previousScanline[4LL * x] + pixel);
460 *dstp = clamp(delta);
466 while (nRunLength > 0)
468 const INT16 deltaValue =
469 WINPR_ASSERTING_INT_CAST(int16_t, pixel + previousScanline[4LL * x]);
470 *dstp = clamp(deltaValue);
478 previousScanline = currentScanline;
481 return (INT32)(srcp - pSrcData);
484 static INLINE INT32 planar_set_plane(BYTE bValue, BYTE* pDstData, UINT32 nDstStep, UINT32 nXDst,
485 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 nChannel,
492 WINPR_ASSERT(nHeight <= INT32_MAX);
493 WINPR_ASSERT(nWidth <= INT32_MAX);
494 WINPR_ASSERT(nDstStep <= INT32_MAX);
498 beg = (INT32)nHeight - 1;
505 end = (INT32)nHeight;
509 for (INT32 y = beg; y != end; y += inc)
511 const intptr_t off = ((1LL * nYDst + y) * nDstStep) + (4LL * nXDst) + nChannel * 1LL;
512 BYTE* dstp = &pDstData[off];
514 for (INT32 x = 0; x < (INT32)nWidth; ++x)
524 static INLINE BOOL writeLine(BYTE** WINPR_RESTRICT ppRgba, UINT32 DstFormat, UINT32 width,
525 const BYTE** WINPR_RESTRICT ppR,
const BYTE** WINPR_RESTRICT ppG,
526 const BYTE** WINPR_RESTRICT ppB,
const BYTE** WINPR_RESTRICT ppA)
528 WINPR_ASSERT(ppRgba);
535 case PIXEL_FORMAT_BGRA32:
536 for (UINT32 x = 0; x < width; x++)
538 *(*ppRgba)++ = *(*ppB)++;
539 *(*ppRgba)++ = *(*ppG)++;
540 *(*ppRgba)++ = *(*ppR)++;
541 *(*ppRgba)++ = *(*ppA)++;
546 case PIXEL_FORMAT_BGRX32:
547 for (UINT32 x = 0; x < width; x++)
549 *(*ppRgba)++ = *(*ppB)++;
550 *(*ppRgba)++ = *(*ppG)++;
551 *(*ppRgba)++ = *(*ppR)++;
560 for (UINT32 x = 0; x < width; x++)
562 BYTE alpha = *(*ppA)++;
564 FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
565 FreeRDPWriteColor(*ppRgba, DstFormat, color);
566 *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
571 const BYTE alpha = 0xFF;
573 for (UINT32 x = 0; x < width; x++)
576 FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
577 FreeRDPWriteColor(*ppRgba, DstFormat, color);
578 *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
586 static INLINE BOOL planar_decompress_planes_raw(
const BYTE* WINPR_RESTRICT pSrcData[4],
587 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
588 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
589 UINT32 nWidth, UINT32 nHeight, BOOL vFlip,
595 const BYTE* pR = pSrcData[0];
596 const BYTE* pG = pSrcData[1];
597 const BYTE* pB = pSrcData[2];
598 const BYTE* pA = pSrcData[3];
599 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
603 beg = WINPR_ASSERTING_INT_CAST(int32_t, nHeight - 1);
610 end = WINPR_ASSERTING_INT_CAST(int32_t, nHeight);
614 if (nYDst + nHeight > totalHeight)
617 "planar plane destination Y %" PRIu32
" + height %" PRIu32
618 " exceeds totalHeight %" PRIu32,
619 nYDst, nHeight, totalHeight);
623 if ((nXDst + nWidth) * bpp > nDstStep)
626 "planar plane destination (X %" PRIu32
" + width %" PRIu32
") * bpp %" PRIu32
627 " exceeds stride %" PRIu32,
628 nXDst, nWidth, bpp, nDstStep);
632 for (INT32 y = beg; y != end; y += inc)
636 if (y > WINPR_ASSERTING_INT_CAST(INT64, nHeight))
638 WLog_ERR(TAG,
"planar plane destination Y %" PRId32
" exceeds height %" PRIu32, y,
643 const intptr_t off = ((1LL * nYDst + y) * nDstStep) + (1LL * nXDst * bpp);
644 pRGB = &pDstData[off];
646 if (!writeLine(&pRGB, DstFormat, nWidth, &pR, &pG, &pB, &pA))
653 static BOOL planar_subsample_expand(
const BYTE* WINPR_RESTRICT plane,
size_t planeLength,
654 UINT32 nWidth, UINT32 nHeight, UINT32 nPlaneWidth,
655 UINT32 nPlaneHeight, BYTE* WINPR_RESTRICT deltaPlane)
658 WINPR_UNUSED(planeLength);
661 WINPR_ASSERT(deltaPlane);
663 if (nWidth > nPlaneWidth * 2)
665 WLog_ERR(TAG,
"planar subsample width %" PRIu32
" > PlaneWidth %" PRIu32
" * 2", nWidth,
670 if (nHeight > nPlaneHeight * 2)
672 WLog_ERR(TAG,
"planar subsample height %" PRIu32
" > PlaneHeight %" PRIu32
" * 2", nHeight,
677 for (
size_t y = 0; y < nHeight; y++)
679 const BYTE* src = plane + y / 2 * nPlaneWidth;
681 for (UINT32 x = 0; x < nWidth; x++)
683 deltaPlane[pos++] = src[x / 2];
690 BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
691 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 nSrcWidth,
692 UINT32 nSrcHeight, BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
693 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
694 UINT32 nDstHeight, BOOL vFlip)
696 BOOL useAlpha = FALSE;
698 INT32 rleSizes[4] = { 0, 0, 0, 0 };
699 UINT32 rawSizes[4] = { 0 };
700 UINT32 rawWidths[4] = { 0 };
701 UINT32 rawHeights[4] = { 0 };
702 const BYTE* planes[4] = { 0 };
703 const UINT32 w = MIN(nSrcWidth, nDstWidth);
704 const UINT32 h = MIN(nSrcHeight, nDstHeight);
707 WINPR_ASSERT(planar);
711 nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat);
713 const BYTE* srcp = pSrcData;
717 WLog_ERR(TAG,
"Invalid argument pSrcData=NULL");
723 WLog_ERR(TAG,
"Invalid argument pDstData=NULL");
727 const BYTE FormatHeader = *srcp++;
728 const BYTE cll = (FormatHeader & PLANAR_FORMAT_HEADER_CLL_MASK);
729 const BYTE cs = (FormatHeader & PLANAR_FORMAT_HEADER_CS) ? TRUE : FALSE;
730 const BYTE rle = (FormatHeader & PLANAR_FORMAT_HEADER_RLE) ? TRUE : FALSE;
731 const BYTE alpha = (FormatHeader & PLANAR_FORMAT_HEADER_NA) ? FALSE : TRUE;
733 DstFormat = planar_invert_format(planar, alpha, DstFormat);
736 useAlpha = FreeRDPColorHasAlpha(DstFormat);
743 WLog_ERR(TAG,
"Chroma subsampling requires YCoCg and does not work with RGB data");
747 const UINT32 subWidth = (nSrcWidth / 2) + (nSrcWidth % 2);
748 const UINT32 subHeight = (nSrcHeight / 2) + (nSrcHeight % 2);
749 const UINT32 planeSize = nSrcWidth * nSrcHeight;
750 const UINT32 subSize = subWidth * subHeight;
754 rawSizes[0] = planeSize;
755 rawWidths[0] = nSrcWidth;
756 rawHeights[0] = nSrcHeight;
757 rawSizes[1] = planeSize;
758 rawWidths[1] = nSrcWidth;
759 rawHeights[1] = nSrcHeight;
760 rawSizes[2] = planeSize;
761 rawWidths[2] = nSrcWidth;
762 rawHeights[2] = nSrcHeight;
763 rawSizes[3] = planeSize;
764 rawWidths[3] = nSrcWidth;
765 rawHeights[3] = nSrcHeight;
769 rawSizes[0] = planeSize;
770 rawWidths[0] = nSrcWidth;
771 rawHeights[0] = nSrcHeight;
772 rawSizes[1] = subSize;
773 rawWidths[1] = subWidth;
774 rawHeights[1] = subHeight;
775 rawSizes[2] = subSize;
776 rawWidths[2] = subWidth;
777 rawHeights[2] = subHeight;
778 rawSizes[3] = planeSize;
779 rawWidths[3] = nSrcWidth;
780 rawHeights[3] = nSrcHeight;
783 const size_t diff = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(srcp - pSrcData));
786 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
793 UINT32 base = planeSize * 3;
795 base = planeSize + planeSize / 2;
799 if ((SrcSize - diff) < (planeSize + base))
801 WLog_ERR(TAG,
"Alpha plane size mismatch %" PRIuz
" < %" PRIu32, SrcSize - diff,
807 planes[0] = planes[3] + rawSizes[3];
808 planes[1] = planes[0] + rawSizes[0];
809 planes[2] = planes[1] + rawSizes[1];
811 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
813 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p", planes[2], rawSizes[2],
820 if ((SrcSize - diff) < base)
822 WLog_ERR(TAG,
"plane size mismatch %" PRIu32
" < %" PRIu32, SrcSize - diff, base);
827 planes[1] = planes[0] + rawSizes[0];
828 planes[2] = planes[1] + rawSizes[1];
830 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
832 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p", planes[2], rawSizes[2],
843 rleSizes[3] = planar_skip_plane_rle(planes[3], (UINT32)(SrcSize - diff), rawWidths[3],
849 planes[0] = planes[3] + rleSizes[3];
854 const size_t diff0 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[0] - pSrcData));
857 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff0);
860 rleSizes[0] = planar_skip_plane_rle(planes[0], (UINT32)(SrcSize - diff0), rawWidths[0],
866 planes[1] = planes[0] + rleSizes[0];
868 const size_t diff1 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[1] - pSrcData));
871 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff1);
874 rleSizes[1] = planar_skip_plane_rle(planes[1], (UINT32)(SrcSize - diff1), rawWidths[1],
880 planes[2] = planes[1] + rleSizes[1];
881 const size_t diff2 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[2] - pSrcData));
884 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
887 rleSizes[2] = planar_skip_plane_rle(planes[2], (UINT32)(SrcSize - diff2), rawWidths[2],
896 UINT32 TempFormat = 0;
897 BYTE* pTempData = pDstData;
898 UINT32 nTempStep = nDstStep;
899 UINT32 nTotalHeight = nYDst + nDstHeight;
902 TempFormat = PIXEL_FORMAT_BGRA32;
904 TempFormat = PIXEL_FORMAT_BGRX32;
906 TempFormat = planar_invert_format(planar, alpha, TempFormat);
908 if ((TempFormat != DstFormat) || (nSrcWidth != nDstWidth) || (nSrcHeight != nDstHeight))
910 pTempData = planar->pTempData;
911 nTempStep = planar->nTempStep;
912 nTotalHeight = planar->maxHeight;
917 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
918 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
922 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
924 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
926 if ((SrcSize - (srcp - pSrcData)) == 1)
931 status = planar_decompress_plane_rle(
932 planes[0], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[0]), pTempData, nTempStep,
933 nXDst, nYDst, nSrcWidth, nSrcHeight, 2, vFlip);
938 status = planar_decompress_plane_rle(
939 planes[1], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[1]), pTempData, nTempStep,
940 nXDst, nYDst, nSrcWidth, nSrcHeight, 1, vFlip);
945 status = planar_decompress_plane_rle(
946 planes[2], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[2]), pTempData, nTempStep,
947 nXDst, nYDst, nSrcWidth, nSrcHeight, 0, vFlip);
952 srcp += rleSizes[0] + rleSizes[1] + rleSizes[2];
956 status = planar_decompress_plane_rle(
957 planes[3], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[3]), pTempData,
958 nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 3, vFlip);
961 status = planar_set_plane(0xFF, pTempData, nTempStep, nXDst, nYDst, nSrcWidth,
962 nSrcHeight, 3, vFlip);
971 if (pTempData != pDstData)
973 if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, w, h,
974 pTempData, TempFormat, nTempStep, nXDst, nYDst, NULL,
977 WLog_ERR(TAG,
"planar image copy failed");
984 UINT32 TempFormat = 0;
985 BYTE* pTempData = planar->pTempData;
986 UINT32 nTempStep = planar->nTempStep;
987 UINT32 nTotalHeight = planar->maxHeight;
988 BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
991 TempFormat = PIXEL_FORMAT_BGRA32;
993 TempFormat = PIXEL_FORMAT_BGRX32;
1000 BYTE* rleBuffer[4] = { 0 };
1002 if (!planar->rlePlanesBuffer)
1005 rleBuffer[3] = planar->rlePlanesBuffer;
1006 rleBuffer[0] = rleBuffer[3] + planeSize;
1007 rleBuffer[1] = rleBuffer[0] + planeSize;
1008 rleBuffer[2] = rleBuffer[1] + planeSize;
1011 status = planar_decompress_plane_rle_only(
1012 planes[3], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[3]), rleBuffer[3],
1013 rawWidths[3], rawHeights[3]);
1020 srcp += rleSizes[3];
1022 status = planar_decompress_plane_rle_only(
1023 planes[0], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[0]), rleBuffer[0],
1024 rawWidths[0], rawHeights[0]);
1029 status = planar_decompress_plane_rle_only(
1030 planes[1], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[1]), rleBuffer[1],
1031 rawWidths[1], rawHeights[1]);
1036 status = planar_decompress_plane_rle_only(
1037 planes[2], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[2]), rleBuffer[2],
1038 rawWidths[2], rawHeights[2]);
1043 planes[0] = rleBuffer[0];
1044 planes[1] = rleBuffer[1];
1045 planes[2] = rleBuffer[2];
1046 planes[3] = rleBuffer[3];
1055 if (!planar_subsample_expand(planes[1], rawSizes[1], nSrcWidth, nSrcHeight,
1056 rawWidths[1], rawHeights[1], planar->deltaPlanes[0]))
1059 planes[1] = planar->deltaPlanes[0];
1060 rawSizes[1] = planeSize;
1061 rawWidths[1] = nSrcWidth;
1062 rawHeights[1] = nSrcHeight;
1064 if (!planar_subsample_expand(planes[2], rawSizes[2], nSrcWidth, nSrcHeight,
1065 rawWidths[2], rawHeights[2], planar->deltaPlanes[1]))
1068 planes[2] = planar->deltaPlanes[1];
1069 rawSizes[2] = planeSize;
1070 rawWidths[2] = nSrcWidth;
1071 rawHeights[2] = nSrcHeight;
1074 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
1075 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
1079 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
1081 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
1083 if ((SrcSize - (srcp - pSrcData)) == 1)
1087 WINPR_ASSERT(prims->YCoCgToRGB_8u_AC4R);
1088 int rc = prims->YCoCgToRGB_8u_AC4R(
1089 pTempData, WINPR_ASSERTING_INT_CAST(int32_t, nTempStep), dst, DstFormat,
1090 WINPR_ASSERTING_INT_CAST(int32_t, nDstStep), w, h, cll, useAlpha);
1091 if (rc != PRIMITIVES_SUCCESS)
1093 WLog_ERR(TAG,
"YCoCgToRGB_8u_AC4R failed with %d", rc);
1102 static INLINE BOOL freerdp_split_color_planes(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
1103 const BYTE* WINPR_RESTRICT data, UINT32 format,
1104 UINT32 width, UINT32 height, UINT32 scanline,
1105 BYTE* WINPR_RESTRICT planes[4])
1107 WINPR_ASSERT(planar);
1109 if ((width > INT32_MAX) || (height > INT32_MAX) || (scanline > INT32_MAX))
1113 scanline = width * FreeRDPGetBytesPerPixel(format);
1115 if (planar->topdown)
1118 for (UINT32 i = 0; i < height; i++)
1120 const BYTE* pixel = &data[1ULL * scanline * i];
1122 for (UINT32 j = 0; j < width; j++)
1124 const UINT32 color = FreeRDPReadColor(pixel, format);
1125 pixel += FreeRDPGetBytesPerPixel(format);
1126 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1127 &planes[0][k], NULL);
1136 for (INT64 i = (INT64)height - 1; i >= 0; i--)
1138 const BYTE* pixel = &data[1ULL * scanline * (UINT32)i];
1140 for (UINT32 j = 0; j < width; j++)
1142 const UINT32 color = FreeRDPReadColor(pixel, format);
1143 pixel += FreeRDPGetBytesPerPixel(format);
1144 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1145 &planes[0][k], NULL);
1153 static INLINE UINT32 freerdp_bitmap_planar_write_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1154 UINT32 cRawBytes, UINT32 nRunLength,
1155 BYTE* WINPR_RESTRICT pOutBuffer,
1156 UINT32 outBufferSize)
1158 const BYTE* pInput = NULL;
1159 BYTE* pOutput = NULL;
1160 BYTE controlByte = 0;
1161 UINT32 nBytesToWrite = 0;
1163 pOutput = pOutBuffer;
1165 if (!cRawBytes && !nRunLength)
1170 cRawBytes += nRunLength;
1178 if (nRunLength > 15)
1180 if (nRunLength < 18)
1182 controlByte = PLANAR_CONTROL_BYTE(13, cRawBytes);
1188 controlByte = PLANAR_CONTROL_BYTE(15, cRawBytes);
1195 controlByte = PLANAR_CONTROL_BYTE(nRunLength, cRawBytes);
1202 controlByte = PLANAR_CONTROL_BYTE(0, 15);
1206 if (outBufferSize < 1)
1210 *pOutput = controlByte;
1212 nBytesToWrite = (controlByte >> 4);
1216 if (outBufferSize < nBytesToWrite)
1219 outBufferSize -= nBytesToWrite;
1220 CopyMemory(pOutput, pInput, nBytesToWrite);
1221 pOutput += nBytesToWrite;
1222 pInput += nBytesToWrite;
1228 if (nRunLength > 47)
1230 if (nRunLength < 50)
1232 controlByte = PLANAR_CONTROL_BYTE(2, 13);
1237 controlByte = PLANAR_CONTROL_BYTE(2, 15);
1241 else if (nRunLength > 31)
1243 controlByte = PLANAR_CONTROL_BYTE(2, (nRunLength - 32));
1246 else if (nRunLength > 15)
1248 controlByte = PLANAR_CONTROL_BYTE(1, (nRunLength - 16));
1253 controlByte = PLANAR_CONTROL_BYTE(nRunLength, 0);
1257 if (outBufferSize < 1)
1261 *pOutput = controlByte;
1265 const intptr_t diff = (pOutput - pOutBuffer);
1266 if ((diff < 0) || (diff > UINT32_MAX))
1268 return (UINT32)diff;
1271 static INLINE UINT32 freerdp_bitmap_planar_encode_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1272 UINT32 inBufferSize,
1273 BYTE* WINPR_RESTRICT pOutBuffer,
1274 UINT32 outBufferSize)
1277 const BYTE* pInput = NULL;
1278 BYTE* pOutput = NULL;
1279 const BYTE* pBytes = NULL;
1280 UINT32 cRawBytes = 0;
1281 UINT32 nRunLength = 0;
1282 UINT32 bSymbolMatch = 0;
1283 UINT32 nBytesWritten = 0;
1284 UINT32 nTotalBytesWritten = 0;
1289 pOutput = pOutBuffer;
1290 nTotalBytesWritten = 0;
1300 bSymbolMatch = (symbol == *pInput) ? TRUE : FALSE;
1305 if (nRunLength && !bSymbolMatch)
1309 cRawBytes += nRunLength;
1314 pBytes = pInput - (cRawBytes + nRunLength + 1);
1315 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1316 pOutput, outBufferSize);
1319 if (!nBytesWritten || (nBytesWritten > outBufferSize))
1322 nTotalBytesWritten += nBytesWritten;
1323 outBufferSize -= nBytesWritten;
1324 pOutput += nBytesWritten;
1329 nRunLength += bSymbolMatch;
1330 cRawBytes += (!bSymbolMatch) ? TRUE : FALSE;
1331 }
while (outBufferSize);
1333 if (cRawBytes || nRunLength)
1335 pBytes = pInput - (cRawBytes + nRunLength);
1336 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1337 pOutput, outBufferSize);
1342 nTotalBytesWritten += nBytesWritten;
1348 return nTotalBytesWritten;
1351 BOOL freerdp_bitmap_planar_compress_plane_rle(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1352 UINT32 height, BYTE* WINPR_RESTRICT outPlane,
1353 UINT32* WINPR_RESTRICT dstSize)
1356 const BYTE* pInput = NULL;
1357 BYTE* pOutput = NULL;
1358 UINT32 outBufferSize = 0;
1359 UINT32 nBytesWritten = 0;
1360 UINT32 nTotalBytesWritten = 0;
1368 outBufferSize = *dstSize;
1369 nTotalBytesWritten = 0;
1371 while (outBufferSize)
1374 freerdp_bitmap_planar_encode_rle_bytes(pInput, width, pOutput, outBufferSize);
1376 if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
1379 outBufferSize -= nBytesWritten;
1380 nTotalBytesWritten += nBytesWritten;
1381 pOutput += nBytesWritten;
1385 if (index >= height)
1389 *dstSize = nTotalBytesWritten;
1393 static INLINE BOOL freerdp_bitmap_planar_compress_planes_rle(BYTE* WINPR_RESTRICT inPlanes[4],
1394 UINT32 width, UINT32 height,
1395 BYTE* WINPR_RESTRICT outPlanes,
1396 UINT32* WINPR_RESTRICT dstSizes,
1399 UINT32 outPlanesSize = width * height * 4;
1408 dstSizes[0] = outPlanesSize;
1410 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[0], width, height, outPlanes,
1414 outPlanes += dstSizes[0];
1415 outPlanesSize -= dstSizes[0];
1419 dstSizes[1] = outPlanesSize;
1421 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[1], width, height, outPlanes,
1425 outPlanes += dstSizes[1];
1426 outPlanesSize -= dstSizes[1];
1428 dstSizes[2] = outPlanesSize;
1430 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[2], width, height, outPlanes,
1434 outPlanes += dstSizes[2];
1435 outPlanesSize -= dstSizes[2];
1437 dstSizes[3] = outPlanesSize;
1439 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[3], width, height, outPlanes,
1446 BYTE* freerdp_bitmap_planar_delta_encode_plane(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1447 UINT32 height, BYTE* WINPR_RESTRICT outPlane)
1449 BYTE* outPtr = NULL;
1450 const BYTE* srcPtr = NULL;
1451 const BYTE* prevLinePtr = NULL;
1455 if (width * height == 0)
1458 if (!(outPlane = (BYTE*)calloc(height, width)))
1463 CopyMemory(outPlane, inPlane, width);
1464 outPtr = outPlane + width;
1465 srcPtr = inPlane + width;
1466 prevLinePtr = inPlane;
1468 for (UINT32 y = 1; y < height; y++)
1470 for (UINT32 x = 0; x < width; x++, outPtr++, srcPtr++, prevLinePtr++)
1472 INT32 delta = *srcPtr - *prevLinePtr;
1473 BYTE s2c = WINPR_ASSERTING_INT_CAST(
1474 BYTE, (delta >= 0) ? delta : (~((BYTE)(-delta)) + 1) & 0xFF);
1475 s2c = WINPR_ASSERTING_INT_CAST(
1477 (s2c >= 0) ? (s2c << 1) & 0xFF : (((UINT32)(~((BYTE)s2c) + 1) << 1) - 1) & 0xFF);
1485 static INLINE BOOL freerdp_bitmap_planar_delta_encode_planes(BYTE* WINPR_RESTRICT inPlanes[4],
1486 UINT32 width, UINT32 height,
1487 BYTE* WINPR_RESTRICT outPlanes[4])
1489 for (UINT32 i = 0; i < 4; i++)
1492 freerdp_bitmap_planar_delta_encode_plane(inPlanes[i], width, height, outPlanes[i]);
1501 BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1502 const BYTE* WINPR_RESTRICT data, UINT32 format, UINT32 width,
1503 UINT32 height, UINT32 scanline, BYTE* WINPR_RESTRICT dstData,
1504 UINT32* WINPR_RESTRICT pDstSize)
1508 UINT32 planeSize = 0;
1509 UINT32 dstSizes[4] = { 0 };
1510 BYTE FormatHeader = 0;
1512 if (!context || !context->rlePlanesBuffer)
1515 if (context->AllowSkipAlpha)
1516 FormatHeader |= PLANAR_FORMAT_HEADER_NA;
1518 planeSize = width * height;
1520 if (!context->AllowSkipAlpha)
1521 format = planar_invert_format(context, TRUE, format);
1523 if (!freerdp_split_color_planes(context, data, format, width, height, scanline,
1527 if (context->AllowRunLengthEncoding)
1529 if (!freerdp_bitmap_planar_delta_encode_planes(context->planes, width, height,
1530 context->deltaPlanes))
1533 if (!freerdp_bitmap_planar_compress_planes_rle(context->deltaPlanes, width, height,
1534 context->rlePlanesBuffer, dstSizes,
1535 context->AllowSkipAlpha))
1539 uint32_t offset = 0;
1540 FormatHeader |= PLANAR_FORMAT_HEADER_RLE;
1541 context->rlePlanes[0] = &context->rlePlanesBuffer[offset];
1542 offset += dstSizes[0];
1543 context->rlePlanes[1] = &context->rlePlanesBuffer[offset];
1544 offset += dstSizes[1];
1545 context->rlePlanes[2] = &context->rlePlanesBuffer[offset];
1546 offset += dstSizes[2];
1547 context->rlePlanes[3] = &context->rlePlanesBuffer[offset];
1549 #if defined(WITH_DEBUG_CODECS)
1551 "R: [%" PRIu32
"/%" PRIu32
"] G: [%" PRIu32
"/%" PRIu32
"] B: [%" PRIu32
1553 dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize);
1558 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1560 if (!context->AllowRunLengthEncoding)
1563 if (context->rlePlanes[0] == NULL)
1566 if (context->rlePlanes[1] == NULL)
1569 if (context->rlePlanes[2] == NULL)
1572 if (context->rlePlanes[3] == NULL)
1580 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1582 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1583 size += dstSizes[0];
1588 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1589 size += (dstSizes[1] + dstSizes[2] + dstSizes[3]);
1591 size += (planeSize * 3);
1593 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1596 dstData = malloc(size);
1605 *dstp = FormatHeader;
1610 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1612 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1614 CopyMemory(dstp, context->rlePlanes[0], dstSizes[0]);
1615 dstp += dstSizes[0];
1619 CopyMemory(dstp, context->planes[0], planeSize);
1626 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1628 CopyMemory(dstp, context->rlePlanes[1], dstSizes[1]);
1629 dstp += dstSizes[1];
1633 CopyMemory(dstp, context->planes[1], planeSize);
1639 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1641 CopyMemory(dstp, context->rlePlanes[2], dstSizes[2]);
1642 dstp += dstSizes[2];
1646 CopyMemory(dstp, context->planes[2], planeSize);
1652 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1654 CopyMemory(dstp, context->rlePlanes[3], dstSizes[3]);
1655 dstp += dstSizes[3];
1659 CopyMemory(dstp, context->planes[3], planeSize);
1665 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1671 const intptr_t diff = (dstp - dstData);
1672 if ((diff < 0) || (diff > UINT32_MAX))
1677 size = (UINT32)diff;
1682 BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1683 UINT32 width, UINT32 height)
1688 context->bgr = FALSE;
1689 context->maxWidth = PLANAR_ALIGN(width, 4);
1690 context->maxHeight = PLANAR_ALIGN(height, 4);
1692 const UINT64 tmp = (UINT64)context->maxWidth * context->maxHeight;
1693 if (tmp > UINT32_MAX)
1695 context->maxPlaneSize = (UINT32)tmp;
1698 if (context->maxWidth > UINT32_MAX / 4)
1700 context->nTempStep = context->maxWidth * 4;
1702 memset((
void*)context->planes, 0,
sizeof(context->planes));
1703 memset((
void*)context->rlePlanes, 0,
sizeof(context->rlePlanes));
1704 memset((
void*)context->deltaPlanes, 0,
sizeof(context->deltaPlanes));
1706 if (context->maxPlaneSize > 0)
1708 void* tmp = winpr_aligned_recalloc(context->planesBuffer, context->maxPlaneSize, 4, 32);
1711 context->planesBuffer = tmp;
1713 tmp = winpr_aligned_recalloc(context->pTempData, context->maxPlaneSize, 6, 32);
1716 context->pTempData = tmp;
1718 tmp = winpr_aligned_recalloc(context->deltaPlanesBuffer, context->maxPlaneSize, 4, 32);
1721 context->deltaPlanesBuffer = tmp;
1723 tmp = winpr_aligned_recalloc(context->rlePlanesBuffer, context->maxPlaneSize, 4, 32);
1726 context->rlePlanesBuffer = tmp;
1728 context->planes[0] = &context->planesBuffer[0ULL * context->maxPlaneSize];
1729 context->planes[1] = &context->planesBuffer[1ULL * context->maxPlaneSize];
1730 context->planes[2] = &context->planesBuffer[2ULL * context->maxPlaneSize];
1731 context->planes[3] = &context->planesBuffer[3ULL * context->maxPlaneSize];
1732 context->deltaPlanes[0] = &context->deltaPlanesBuffer[0ULL * context->maxPlaneSize];
1733 context->deltaPlanes[1] = &context->deltaPlanesBuffer[1ULL * context->maxPlaneSize];
1734 context->deltaPlanes[2] = &context->deltaPlanesBuffer[2ULL * context->maxPlaneSize];
1735 context->deltaPlanes[3] = &context->deltaPlanesBuffer[3ULL * context->maxPlaneSize];
1740 BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, UINT32 maxWidth,
1743 BITMAP_PLANAR_CONTEXT* context =
1744 (BITMAP_PLANAR_CONTEXT*)winpr_aligned_calloc(1,
sizeof(BITMAP_PLANAR_CONTEXT), 32);
1749 if (flags & PLANAR_FORMAT_HEADER_NA)
1750 context->AllowSkipAlpha = TRUE;
1752 if (flags & PLANAR_FORMAT_HEADER_RLE)
1753 context->AllowRunLengthEncoding = TRUE;
1755 if (flags & PLANAR_FORMAT_HEADER_CS)
1756 context->AllowColorSubsampling = TRUE;
1758 context->ColorLossLevel = flags & PLANAR_FORMAT_HEADER_CLL_MASK;
1760 if (context->ColorLossLevel)
1761 context->AllowDynamicColorFidelity = TRUE;
1763 if (!freerdp_bitmap_planar_context_reset(context, maxWidth, maxHeight))
1765 WINPR_PRAGMA_DIAG_PUSH
1766 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1767 freerdp_bitmap_planar_context_free(context);
1768 WINPR_PRAGMA_DIAG_POP
1775 void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context)
1780 winpr_aligned_free(context->pTempData);
1781 winpr_aligned_free(context->planesBuffer);
1782 winpr_aligned_free(context->deltaPlanesBuffer);
1783 winpr_aligned_free(context->rlePlanesBuffer);
1784 winpr_aligned_free(context);
1787 void freerdp_planar_switch_bgr(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL bgr)
1789 WINPR_ASSERT(planar);
1793 void freerdp_planar_topdown_image(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL topdown)
1795 WINPR_ASSERT(planar);
1796 planar->topdown = topdown;