libfreerdp-codec: improve ClearCodec decompressor
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 26 Jun 2014 21:08:51 +0000 (17:08 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 26 Jun 2014 21:08:51 +0000 (17:08 -0400)
client/X11/xf_gfx.c
include/freerdp/codec/clear.h
libfreerdp/codec/clear.c
libfreerdp/codec/test/TestFreeRDPCodecClear.c

index 4ebbe54..01ec060 100644 (file)
@@ -270,10 +270,12 @@ int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, R
        status = clear_decompress(NULL, cmd->data, cmd->length, &DstData,
                        PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height);
 
+#if 0
        /* fill with pink for now to distinguish from the rest */
 
        freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
                        cmd->left, cmd->top, cmd->width, cmd->height, 0xFF69B4);
+#endif
 
        invalidRect.left = cmd->left;
        invalidRect.top = cmd->top;
index fdb59e9..03aed70 100644 (file)
@@ -23,6 +23,8 @@
 #include <freerdp/api.h>
 #include <freerdp/types.h>
 
+#include <freerdp/codec/color.h>
+
 #define CLEARCODEC_FLAG_GLYPH_INDEX    0x01
 #define CLEARCODEC_FLAG_GLYPH_HIT      0x02
 #define CLEARCODEC_FLAG_CACHE_RESET    0x03
index c67cfa2..40dcfc2 100644 (file)
 #include <freerdp/codec/color.h>
 #include <freerdp/codec/clear.h>
 
+static UINT32 CLEAR_LOG2_FLOOR[256] =
+{
+       0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+static BYTE CLEAR_8BIT_MASKS[9] =
+{
+       0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
+};
+
 int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
                BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight)
 {
-       int index;
+       UINT32 i;
+       UINT32 count;
+       BYTE r, g, b;
+       UINT32 color;
        BYTE glyphFlags;
        BYTE seqNumber;
        UINT16 glyphIndex;
        UINT32 offset = 0;
+       BYTE* pDstData = NULL;
        UINT32 residualByteCount;
        UINT32 bandsByteCount;
        UINT32 subcodecByteCount;
+       BYTE runLengthFactor1;
+       UINT16 runLengthFactor2;
+       UINT32 runLengthFactor3;
+       UINT32 runLengthFactor;
+
+       if (!ppDstData)
+               return -1;
+
+       pDstData = *ppDstData;
+
+       if (!pDstData)
+               return -1;
 
        if (SrcSize < 2)
                return -1001;
@@ -83,17 +124,12 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
 
        if (residualByteCount > 0)
        {
-               UINT32 color;
-               BYTE blueValue;
-               BYTE greenValue;
-               BYTE redValue;
                UINT32 suboffset;
                BYTE* residualData;
+               UINT32* pDstPixel;
+               UINT32 pixelX, pixelY;
                UINT32 pixelIndex = 0;
-               BYTE runLengthFactor1 = 0;
-               UINT16 runLengthFactor2 = 0;
-               UINT32 runLengthFactor3 = 0;
-               UINT32 runLengthFactor = 0;
+               UINT32 pixelCount = 0;
 
                if ((SrcSize - offset) < residualByteCount)
                        return -1004;
@@ -106,10 +142,10 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
                        if ((residualByteCount - suboffset) < 4)
                                return -1005;
 
-                       blueValue = residualData[suboffset];
-                       greenValue = residualData[suboffset + 1];
-                       redValue = residualData[suboffset + 2];
-                       color = RGB32(redValue, greenValue, blueValue);
+                       b = residualData[suboffset]; /* blueValue */
+                       g = residualData[suboffset + 1]; /* greenValue */
+                       r = residualData[suboffset + 2]; /* redValue */
+                       color = RGB32(r, g, b);
                        suboffset += 3;
 
                        runLengthFactor1 = residualData[suboffset];
@@ -136,8 +172,28 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
                                }
                        }
 
-                       //freerdp_image_fill(*ppDstData, DstFormat, nDstStep,
-                       //              nXDst + (pixelIndex % nWidth), nYDst + (pixelIndex / nWidth), nWidth, nHeight, color);
+                       pixelX = (pixelIndex % nWidth);
+                       pixelY = (pixelIndex - pixelX) / nWidth;
+                       pixelCount = runLengthFactor;
+
+                       while (pixelCount > 0)
+                       {
+                               count = nWidth - pixelX;
+
+                               if (count > pixelCount)
+                                       count = pixelCount;
+
+                               pDstPixel = (UINT32*) &pDstData[((nYDst + pixelY) * nDstStep) + ((nXDst + pixelX) * 4)];
+                               pixelCount -= count;
+
+                               while (count--)
+                               {
+                                       *pDstPixel++ = color;
+                               }
+
+                               pixelX = 0;
+                               pixelY++;
+                       }
 
                        pixelIndex += runLengthFactor;
                }
@@ -169,9 +225,6 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
                        UINT16 xEnd;
                        UINT16 yStart;
                        UINT16 yEnd;
-                       BYTE blueBkg;
-                       BYTE greenBkg;
-                       BYTE redBkg;
                        BYTE* vBars;
                        UINT16 vBarHeader;
                        UINT16 vBarIndex;
@@ -187,17 +240,18 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
                        xEnd = *((UINT16*) &bandsData[suboffset + 2]);
                        yStart = *((UINT16*) &bandsData[suboffset + 4]);
                        yEnd = *((UINT16*) &bandsData[suboffset + 6]);
-                       blueBkg = bandsData[suboffset + 8];
-                       greenBkg = bandsData[suboffset + 9];
-                       redBkg = bandsData[suboffset + 10];
+                       b = bandsData[suboffset + 8]; /* blueBkg */
+                       g = bandsData[suboffset + 9]; /* greenBkg */
+                       r = bandsData[suboffset + 10]; /* redBkg */
+                       color = RGB32(r, g, b);
                        suboffset += 11;
 
                        vBarCount = (xEnd - xStart) + 1;
 
                        printf("CLEARCODEC_BAND: xStart: %d xEnd: %d yStart: %d yEnd: %d vBarCount: %d blueBkg: 0x%02X greenBkg: 0x%02X redBkg: 0x%02X\n",
-                                       xStart, xEnd, yStart, yEnd, vBarCount, blueBkg, greenBkg, redBkg);
+                                       xStart, xEnd, yStart, yEnd, vBarCount, b, g, r);
 
-                       for (index = 0; index < vBarCount; index++)
+                       for (i = 0; i < vBarCount; i++)
                        {
                                vBars = &bandsData[suboffset];
 
@@ -265,10 +319,16 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
                UINT16 width;
                UINT16 height;
                BYTE* bitmapData;
+               UINT32 bitmapDataOffset;
                UINT32 bitmapDataByteCount;
                BYTE subcodecId;
                BYTE* subcodecs;
                UINT32 suboffset;
+               BYTE paletteCount;
+               BYTE* paletteEntries;
+               BYTE stopIndex;
+               BYTE suiteDepth;
+               UINT32 numBits;
 
                if ((SrcSize - offset) < subcodecByteCount)
                        return -1015;
@@ -297,6 +357,66 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
 
                        bitmapData = &subcodecs[suboffset];
 
+                       if (subcodecId == 0) /* Uncompressed */
+                       {
+
+                       }
+                       else if (subcodecId == 1) /* NSCodec */
+                       {
+
+                       }
+                       else if (subcodecId == 2) /* CLEARCODEC_SUBCODEC_RLEX */
+                       {
+                               paletteCount = bitmapData[0];
+                               paletteEntries = &bitmapData[1];
+                               bitmapDataOffset = 1 + (paletteCount * 3);
+
+                               for (i = 0; i < paletteCount; i++)
+                               {
+                                       b = paletteEntries[(i * 3) + 0]; /* blue */
+                                       g = paletteEntries[(i * 3) + 1]; /* green */
+                                       r = paletteEntries[(i * 3) + 2]; /* red */
+                               }
+
+                               numBits = CLEAR_LOG2_FLOOR[paletteCount - 1] + 1;
+
+                               while (bitmapDataOffset < bitmapDataByteCount)
+                               {
+                                       stopIndex = bitmapData[bitmapDataOffset] & CLEAR_8BIT_MASKS[numBits];
+                                       suiteDepth = (bitmapData[bitmapDataOffset] >> numBits) & CLEAR_8BIT_MASKS[numBits];
+                                       bitmapDataOffset++;
+
+                                       runLengthFactor1 = bitmapData[bitmapDataOffset];
+                                       runLengthFactor = runLengthFactor1;
+                                       bitmapDataOffset += 1;
+
+                                       if (runLengthFactor1 >= 0xFF)
+                                       {
+                                               if ((bitmapDataByteCount - bitmapDataOffset) < 2)
+                                                       return -1;
+
+                                               runLengthFactor2 = *((UINT16*) &bitmapData[bitmapDataOffset]);
+                                               runLengthFactor = runLengthFactor2;
+                                               bitmapDataOffset += 2;
+
+                                               if (runLengthFactor2 >= 0xFFFF)
+                                               {
+                                                       if ((bitmapDataByteCount - bitmapDataOffset) < 4)
+                                                               return -1;
+
+                                                       runLengthFactor3 = *((UINT32*) &bitmapData[bitmapDataOffset]);
+                                                       runLengthFactor = runLengthFactor3;
+                                                       bitmapDataOffset += 4;
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               fprintf(stderr, "clear_decompress: unknown subcodecId: %d\n", subcodecId);
+                               return -1;
+                       }
+
                        suboffset += bitmapDataByteCount;
                }
 
index fcec61a..4b65ac8 100644 (file)
@@ -42,7 +42,6 @@ int test_ClearDecompressExample1()
        int status;
        BYTE* pSrcData;
        UINT32 SrcSize;
-       UINT32 DstSize;
        BYTE* pDstData = NULL;
        CLEAR_CONTEXT* clear;
 
@@ -51,7 +50,8 @@ int test_ClearDecompressExample1()
        SrcSize = sizeof(TEST_CLEAR_EXAMPLE_1) - 1;
        pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_1;
 
-       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize);
+       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData,
+                       PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0);
 
        printf("clear_decompress example 1 status: %d\n", status);
 
@@ -65,7 +65,6 @@ int test_ClearDecompressExample2()
        int status;
        BYTE* pSrcData;
        UINT32 SrcSize;
-       UINT32 DstSize;
        BYTE* pDstData = NULL;
        CLEAR_CONTEXT* clear;
 
@@ -74,7 +73,8 @@ int test_ClearDecompressExample2()
        SrcSize = sizeof(TEST_CLEAR_EXAMPLE_2) - 1;
        pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_2;
 
-       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize);
+       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData,
+                       PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0);
 
        printf("clear_decompress example 2 status: %d\n", status);
 
@@ -88,7 +88,6 @@ int test_ClearDecompressExample3()
        int status;
        BYTE* pSrcData;
        UINT32 SrcSize;
-       UINT32 DstSize;
        BYTE* pDstData = NULL;
        CLEAR_CONTEXT* clear;
 
@@ -97,7 +96,8 @@ int test_ClearDecompressExample3()
        SrcSize = sizeof(TEST_CLEAR_EXAMPLE_3) - 1;
        pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_3;
 
-       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize);
+       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData,
+                       PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0);
 
        printf("clear_decompress example 3 status: %d\n", status);
 
@@ -111,7 +111,6 @@ int test_ClearDecompressExample4()
        int status;
        BYTE* pSrcData;
        UINT32 SrcSize;
-       UINT32 DstSize;
        BYTE* pDstData = NULL;
        CLEAR_CONTEXT* clear;
 
@@ -120,7 +119,8 @@ int test_ClearDecompressExample4()
        SrcSize = sizeof(TEST_CLEAR_EXAMPLE_4) - 1;
        pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_4;
 
-       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize);
+       status = clear_decompress(clear, pSrcData, SrcSize, &pDstData,
+                       PIXEL_FORMAT_XRGB32, 0, 0, 0, 0, 0);
 
        printf("clear_decompress example 4 status: %d\n", status);