Merge pull request #11880 from akallabeth/planar

Planar fix sign
This commit is contained in:
akallabeth
2025-09-22 20:08:57 +02:00
committed by GitHub
6 changed files with 103 additions and 98 deletions

View File

@@ -25,6 +25,7 @@
#include <winpr/cast.h>
#include <winpr/crt.h>
#include <freerdp/config.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
@@ -38,20 +39,6 @@ extern "C"
{
#endif
static inline BYTE PLANAR_CONTROL_BYTE(UINT32 nRunLength, UINT32 cRawBytes)
{
return WINPR_ASSERTING_INT_CAST(UINT8, ((nRunLength & 0x0F) | ((cRawBytes & 0x0F) << 4)));
}
static inline BYTE PLANAR_CONTROL_BYTE_RUN_LENGTH(UINT32 controlByte)
{
return (controlByte & 0x0F);
}
static inline BYTE PLANAR_CONTROL_BYTE_RAW_BYTES(UINT32 controlByte)
{
return ((controlByte >> 4) & 0x0F);
}
typedef struct S_BITMAP_PLANAR_CONTEXT BITMAP_PLANAR_CONTEXT;
FREERDP_API BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
@@ -74,12 +61,21 @@ extern "C"
FREERDP_API void freerdp_planar_topdown_image(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
BOOL topdown);
FREERDP_API BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
UINT32 nSrcWidth, UINT32 nSrcHeight,
BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
UINT32 nDstWidth, UINT32 nDstHeight, BOOL vFlip);
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
WINPR_DEPRECATED_VAR("use freerdp_bitmap_decompress_planar instead",
FREERDP_API BOOL planar_decompress(
BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 nSrcWidth,
UINT32 nSrcHeight, BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
UINT32 nDstHeight, BOOL vFlip));
#endif
FREERDP_API BOOL freerdp_bitmap_decompress_planar(
BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, const BYTE* WINPR_RESTRICT pSrcData,
UINT32 SrcSize, UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE* WINPR_RESTRICT pDstData,
UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
UINT32 nDstHeight, BOOL vFlip);
#ifdef __cplusplus
}

View File

@@ -96,10 +96,24 @@ struct S_BITMAP_PLANAR_CONTEXT
BOOL topdown;
};
static inline BYTE PLANAR_CONTROL_BYTE(UINT32 nRunLength, UINT32 cRawBytes)
{
return WINPR_ASSERTING_INT_CAST(UINT8, ((nRunLength & 0x0F) | ((cRawBytes & 0x0F) << 4)));
}
static inline BYTE PLANAR_CONTROL_BYTE_RUN_LENGTH(UINT32 controlByte)
{
return (controlByte & 0x0F);
}
static inline BYTE PLANAR_CONTROL_BYTE_RAW_BYTES(UINT32 controlByte)
{
return ((controlByte >> 4) & 0x0F);
}
static INLINE UINT32 planar_invert_format(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL alpha,
UINT32 DstFormat)
{
WINPR_ASSERT(planar);
if (planar->bgr && alpha)
{
switch (DstFormat)
@@ -361,8 +375,6 @@ static INLINE INT32 planar_decompress_plane_rle(const BYTE* WINPR_RESTRICT pSrcD
WINPR_ASSERT(nWidth <= INT32_MAX);
WINPR_ASSERT(nDstStep <= INT32_MAX);
previousScanline = NULL;
if (vFlip)
{
beg = (INT32)nHeight - 1;
@@ -486,8 +498,8 @@ static INLINE INT32 planar_set_plane(BYTE bValue, BYTE* pDstData, UINT32 nDstSte
BOOL vFlip)
{
INT32 beg = 0;
INT32 end = 0;
INT32 inc = 0;
INT32 end = (INT32)nHeight;
INT32 inc = 1;
WINPR_ASSERT(nHeight <= INT32_MAX);
WINPR_ASSERT(nWidth <= INT32_MAX);
@@ -499,12 +511,6 @@ static INLINE INT32 planar_set_plane(BYTE bValue, BYTE* pDstData, UINT32 nDstSte
end = -1;
inc = -1;
}
else
{
beg = 0;
end = (INT32)nHeight;
inc = 1;
}
for (INT32 y = beg; y != end; y += inc)
{
@@ -687,11 +693,25 @@ static BOOL planar_subsample_expand(const BYTE* WINPR_RESTRICT plane, size_t pla
return TRUE;
}
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 nSrcWidth,
UINT32 nSrcHeight, BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
UINT32 nDstHeight, BOOL vFlip)
{
return freerdp_bitmap_decompress_planar(planar, pSrcData, SrcSize, nSrcWidth, nSrcHeight,
pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
nDstHeight, vFlip);
}
#endif
BOOL freerdp_bitmap_decompress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
UINT32 nSrcWidth, UINT32 nSrcHeight,
BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
UINT32 nDstHeight, BOOL vFlip)
{
BOOL useAlpha = FALSE;
INT32 status = 0;
@@ -1155,12 +1175,10 @@ static INLINE UINT32 freerdp_bitmap_planar_write_rle_bytes(const BYTE* WINPR_RES
BYTE* WINPR_RESTRICT pOutBuffer,
UINT32 outBufferSize)
{
const BYTE* pInput = NULL;
BYTE* pOutput = NULL;
const BYTE* pInput = pInBuffer;
BYTE* pOutput = pOutBuffer;
BYTE controlByte = 0;
UINT32 nBytesToWrite = 0;
pInput = pInBuffer;
pOutput = pOutBuffer;
if (!cRawBytes && !nRunLength)
return 0;
@@ -1274,20 +1292,13 @@ static INLINE UINT32 freerdp_bitmap_planar_encode_rle_bytes(const BYTE* WINPR_RE
UINT32 outBufferSize)
{
BYTE symbol = 0;
const BYTE* pInput = NULL;
BYTE* pOutput = NULL;
const BYTE* pInput = pInBuffer;
BYTE* pOutput = pOutBuffer;
const BYTE* pBytes = NULL;
UINT32 cRawBytes = 0;
UINT32 nRunLength = 0;
UINT32 bSymbolMatch = 0;
UINT32 nBytesWritten = 0;
UINT32 nTotalBytesWritten = 0;
symbol = 0;
cRawBytes = 0;
nRunLength = 0;
pInput = pInBuffer;
pOutput = pOutBuffer;
nTotalBytesWritten = 0;
if (!outBufferSize)
return 0;
@@ -1297,7 +1308,7 @@ static INLINE UINT32 freerdp_bitmap_planar_encode_rle_bytes(const BYTE* WINPR_RE
if (!inBufferSize)
break;
bSymbolMatch = (symbol == *pInput) ? TRUE : FALSE;
const UINT32 bSymbolMatch = (symbol == *pInput) ? TRUE : FALSE;
symbol = *pInput;
pInput++;
inBufferSize--;
@@ -1352,25 +1363,18 @@ BOOL freerdp_bitmap_planar_compress_plane_rle(const BYTE* WINPR_RESTRICT inPlane
UINT32 height, BYTE* WINPR_RESTRICT outPlane,
UINT32* WINPR_RESTRICT dstSize)
{
UINT32 index = 0;
const BYTE* pInput = NULL;
BYTE* pOutput = NULL;
UINT32 outBufferSize = 0;
UINT32 nBytesWritten = 0;
UINT32 nTotalBytesWritten = 0;
if (!outPlane)
return FALSE;
index = 0;
pInput = inPlane;
pOutput = outPlane;
outBufferSize = *dstSize;
nTotalBytesWritten = 0;
UINT32 index = 0;
const BYTE* pInput = inPlane;
BYTE* pOutput = outPlane;
UINT32 outBufferSize = *dstSize;
UINT32 nTotalBytesWritten = 0;
while (outBufferSize)
while (outBufferSize > 0)
{
nBytesWritten =
const UINT32 nBytesWritten =
freerdp_bitmap_planar_encode_rle_bytes(pInput, width, pOutput, outBufferSize);
if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
@@ -1446,35 +1450,33 @@ static INLINE BOOL freerdp_bitmap_planar_compress_planes_rle(BYTE* WINPR_RESTRIC
BYTE* freerdp_bitmap_planar_delta_encode_plane(const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
UINT32 height, BYTE* WINPR_RESTRICT outPlane)
{
BYTE* outPtr = NULL;
const BYTE* srcPtr = NULL;
const BYTE* prevLinePtr = NULL;
if (!outPlane)
{
if (width * height == 0)
return NULL;
if (!(outPlane = (BYTE*)calloc(height, width)))
outPlane = (BYTE*)calloc(height, width);
if (!outPlane)
return NULL;
}
// first line is copied as is
CopyMemory(outPlane, inPlane, width);
outPtr = outPlane + width;
srcPtr = inPlane + width;
prevLinePtr = inPlane;
for (UINT32 y = 1; y < height; y++)
{
for (UINT32 x = 0; x < width; x++, outPtr++, srcPtr++, prevLinePtr++)
const size_t off = 1ull * width * y;
BYTE* outPtr = &outPlane[off];
const BYTE* srcPtr = &inPlane[off];
const BYTE* prevLinePtr = &inPlane[off - width];
for (UINT32 x = 0; x < width; x++)
{
const INT32 delta = *srcPtr - *prevLinePtr;
const int s2c1i = (delta >= 0) ? delta : (~((BYTE)(-delta)) + 1);
const char s2c1 = WINPR_CXX_COMPAT_CAST(char, s2c1i & 0xff);
const uint32_t s2c = (s2c1 >= 0) ? ((UINT32)s2c1 << 1)
: (((UINT32)(~((BYTE)(s2c1 & 0xFF)) + 1) << 1) - 1);
*outPtr = (BYTE)s2c;
const int delta = (int)srcPtr[x] - (int)prevLinePtr[x];
const int s2c1i = (delta >= 0) ? delta : (INT_MAX + delta) + 1;
const int8_t s2c1 = WINPR_CXX_COMPAT_CAST(int8_t, s2c1i);
const uint32_t s2c =
(s2c1 >= 0) ? ((UINT32)s2c1 << 1) : (((UINT32)(~(s2c1) + 1) << 1) - 1);
outPtr[x] = (BYTE)s2c;
}
}
@@ -1504,7 +1506,6 @@ BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT conte
{
UINT32 size = 0;
BYTE* dstp = NULL;
UINT32 planeSize = 0;
UINT32 dstSizes[4] = { 0 };
BYTE FormatHeader = 0;
@@ -1514,7 +1515,7 @@ BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT conte
if (context->AllowSkipAlpha)
FormatHeader |= PLANAR_FORMAT_HEADER_NA;
planeSize = width * height;
const UINT32 planeSize = width * height;
if (!context->AllowSkipAlpha)
format = planar_invert_format(context, TRUE, format);

View File

@@ -171,7 +171,7 @@ static void* read_data(const char* type, const char* name, size_t* plength)
cmp = NULL;
fail:
(void)printf("%s: %s %s -> %p\n", __func__, type, name, cmp);
(void)printf("%s: %s %s -> %p\n", __func__, type, name, rc);
free(cmp);
if (fp)
(void)fclose(fp);
@@ -199,9 +199,18 @@ static BOOL compare(const char* type, const char* name, const void* data, size_t
if (!cmp)
goto fail;
if (cmplen != length)
{
(void)printf("%s: %s %s: length mismatch: %" PRIuz " vs %" PRIuz "\n", __func__, type, name,
cmplen, length);
goto fail;
}
if (memcmp(data, cmp, length) != 0)
{
(void)printf("%s: %s %s: data mismatch\n", __func__, type, name);
winpr_HexDump(__func__, WLOG_WARN, data, length);
winpr_HexDump(__func__, WLOG_WARN, cmp, cmplen);
goto fail;
}
rc = TRUE;
fail:
(void)printf("%s: %s %s -> %s\n", __func__, type, name, rc ? "SUCCESS" : "FAILED");
@@ -228,10 +237,6 @@ static BOOL RunTestPlanar(BITMAP_PLANAR_CONTEXT* encplanar, BITMAP_PLANAR_CONTEX
BYTE* decompressedBitmap =
(BYTE*)calloc(height, 1ULL * width * FreeRDPGetBytesPerPixel(dstFormat));
if (!compare("bmp", name, srcBitmap,
1ull * width * height * FreeRDPGetBytesPerPixel(srcFormat)))
goto fail;
if (!compare("enc", name, compressedBitmap, dstSize))
goto fail;
@@ -241,8 +246,9 @@ static BOOL RunTestPlanar(BITMAP_PLANAR_CONTEXT* encplanar, BITMAP_PLANAR_CONTEX
if (!compressedBitmap || !decompressedBitmap)
goto fail;
if (!planar_decompress(decplanar, compressedBitmap, dstSize, width, height, decompressedBitmap,
dstFormat, 0, 0, 0, width, height, FALSE))
if (!freerdp_bitmap_decompress_planar(decplanar, compressedBitmap, dstSize, width, height,
decompressedBitmap, dstFormat, 0, 0, 0, width, height,
FALSE))
{
(void)printf("failed to decompress experimental bitmap 01: width: %" PRIu32
" height: %" PRIu32 "\n",
@@ -321,8 +327,9 @@ static BOOL RunTestPlanarSingleColor(BITMAP_PLANAR_CONTEXT* planar, const UINT32
if (!compressedBitmap)
goto fail_loop;
if (!planar_decompress(planar, compressedBitmap, compressedSize, width, height,
decompressedBitmap, dstFormat, 0, 0, 0, width, height, FALSE))
if (!freerdp_bitmap_decompress_planar(planar, compressedBitmap, compressedSize, width,
height, decompressedBitmap, dstFormat, 0, 0, 0,
width, height, FALSE))
goto fail_loop;
if (!CompareBitmap(decompressedBitmap, dstFormat, bmp, srcFormat, width, height))
@@ -494,9 +501,9 @@ static BOOL FuzzPlanar(void)
FreeRDPGetColorFormatName(DstFormat), nXDst, nYDst, nDstWidth, nDstHeight, nDstStep,
sizeof(dstData));
freerdp_planar_switch_bgr(planar, ((prand(2) % 2) != 0) ? TRUE : FALSE);
planar_decompress(planar, data, dataSize, prand(4096), prand(4096), dstData, DstFormat,
nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
((prand(2) % 2) != 0) ? TRUE : FALSE);
freerdp_bitmap_decompress_planar(planar, data, dataSize, prand(4096), prand(4096), dstData,
DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
((prand(2) % 2) != 0) ? TRUE : FALSE);
}
rc = TRUE;

View File

@@ -1324,9 +1324,9 @@ static int test_dump(int argc, char* argv[])
{
const UINT64 start = winpr_GetTickCount64NS();
if (!planar_decompress(codecs->planar, cmd.data, cmd.length, cmd.width,
cmd.height, dst, DstFormat, stride, cmd.left, cmd.top,
cmd.width, cmd.height, FALSE))
if (!freerdp_bitmap_decompress_planar(
codecs->planar, cmd.data, cmd.length, cmd.width, cmd.height, dst,
DstFormat, stride, cmd.left, cmd.top, cmd.width, cmd.height, FALSE))
success = -1;
const RECTANGLE_16 invalidRect = { .left = (UINT16)MIN(UINT16_MAX, cmd.left),

View File

@@ -540,9 +540,10 @@ static UINT gdi_SurfaceCommand_Planar(rdpGdi* gdi, RdpgfxClientContext* context,
if (!is_within_surface(surface, cmd))
return ERROR_INVALID_DATA;
if (!planar_decompress(surface->codecs->planar, cmd->data, cmd->length, cmd->width, cmd->height,
DstData, surface->format, surface->scanline, cmd->left, cmd->top,
cmd->width, cmd->height, FALSE))
if (!freerdp_bitmap_decompress_planar(surface->codecs->planar, cmd->data, cmd->length,
cmd->width, cmd->height, DstData, surface->format,
surface->scanline, cmd->left, cmd->top, cmd->width,
cmd->height, FALSE))
return ERROR_INTERNAL_ERROR;
invalidRect.left = (UINT16)MIN(UINT16_MAX, cmd->left);

View File

@@ -206,11 +206,11 @@ static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const
const BOOL fidelity =
freerdp_settings_get_bool(context->settings, FreeRDP_DrawAllowDynamicColorFidelity);
freerdp_planar_switch_bgr(context->codecs->planar, fidelity);
if (!planar_decompress(context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight,
bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight,
TRUE))
if (!freerdp_bitmap_decompress_planar(context->codecs->planar, pSrcData, SrcSize,
DstWidth, DstHeight, bitmap->data, bitmap->format,
0, 0, 0, DstWidth, DstHeight, TRUE))
{
WLog_ERR(TAG, "planar_decompress failed");
WLog_ERR(TAG, "freerdp_bitmap_decompress_planar failed");
return FALSE;
}
}