diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 042b4e418..7e8bc649c 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -1641,6 +1641,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, CommandLineSwitchCase(arg, "gfx-progressive") { settings->GfxProgressive = arg->Value ? TRUE : FALSE; + settings->GfxThinClient = settings->GfxProgressive ? FALSE : TRUE; settings->SupportGraphicsPipeline = TRUE; } CommandLineSwitchCase(arg, "gfx-h264") diff --git a/include/freerdp/codec/progressive.h b/include/freerdp/codec/progressive.h index be063aadd..e22ab10fc 100644 --- a/include/freerdp/codec/progressive.h +++ b/include/freerdp/codec/progressive.h @@ -23,19 +23,62 @@ #include #include +#include + #include #include +#define RFX_SUBBAND_DIFFING 0x01 + +#define RFX_TILE_DIFFERENCE 0x01 + +#define RFX_DWT_REDUCE_EXTRAPOLATE 0x01 + #define PROGRESSIVE_WBT_SYNC 0xCCC0 #define PROGRESSIVE_WBT_FRAME_BEGIN 0xCCC1 #define PROGRESSIVE_WBT_FRAME_END 0xCCC2 #define PROGRESSIVE_WBT_CONTEXT 0xCCC3 #define PROGRESSIVE_WBT_REGION 0xCCC4 #define PROGRESSIVE_WBT_TILE_SIMPLE 0xCCC5 -#define PROGRESSIVE_WBT_TILE_PROGRESSIVE_FIRST 0xCCC6 -#define PROGRESSIVE_WBT_TILE_PROGRESSIVE_UPGRADE 0xCCC7 +#define PROGRESSIVE_WBT_TILE_FIRST 0xCCC6 +#define PROGRESSIVE_WBT_TILE_UPGRADE 0xCCC7 -struct _PROGRESSIVE_SYNC +#define PROGRESSIVE_BLOCKS_ALL 0x0001 +#define PROGRESSIVE_BLOCKS_REGION 0x0002 +#define PROGRESSIVE_BLOCKS_TILE 0x0004 + +struct _RFX_PROGRESSIVE_CODEC_QUANT +{ + BYTE quality; + BYTE yQuantValues[5]; + BYTE cbQuantValues[5]; + BYTE crQuantValues[5]; +}; +typedef struct _RFX_PROGRESSIVE_CODEC_QUANT RFX_PROGRESSIVE_CODEC_QUANT; + +struct _RFX_COMPONENT_CODEC_QUANT +{ + BYTE LL3; + BYTE HL3; + BYTE LH3; + BYTE HH3; + BYTE HL2; + BYTE LH2; + BYTE HH2; + BYTE HL1; + BYTE LH1; + BYTE HH1; +}; +typedef struct _RFX_COMPONENT_CODEC_QUANT RFX_COMPONENT_CODEC_QUANT; + +struct _PROGRESSIVE_BLOCK +{ + UINT16 blockType; + UINT32 blockLen; +}; +typedef struct _PROGRESSIVE_BLOCK PROGRESSIVE_BLOCK; + +struct _PROGRESSIVE_BLOCK_SYNC { UINT16 blockType; UINT32 blockLen; @@ -43,45 +86,20 @@ struct _PROGRESSIVE_SYNC UINT32 magic; UINT16 version; }; -typedef struct _PROGRESSIVE_SYNC PROGRESSIVE_SYNC; +typedef struct _PROGRESSIVE_BLOCK_SYNC PROGRESSIVE_BLOCK_SYNC; -struct _PROGRESSIVE_REGION +struct _PROGRESSIVE_BLOCK_CONTEXT { UINT16 blockType; UINT32 blockLen; - BYTE tileSize; - UINT16 numRects; - BYTE numQuant; - BYTE numProgQuant; + BYTE ctxId; + UINT16 tileSize; BYTE flags; - UINT16 numTiles; - UINT32 tileDataSize; - RFX_RECT* rects; - UINT32* quantVals; - UINT32* quantProgVals; }; -typedef struct _PROGRESSIVE_REGION PROGRESSIVE_REGION; +typedef struct _PROGRESSIVE_BLOCK_CONTEXT PROGRESSIVE_BLOCK_CONTEXT; -struct _PROGRESSIVE_FRAME_BEGIN -{ - UINT16 blockType; - UINT32 blockLen; - - UINT32 frameIndex; - UINT16 regionCount; - PROGRESSIVE_REGION* regions; -}; -typedef struct _PROGRESSIVE_FRAME_BEGIN PROGRESSIVE_FRAME_BEGIN; - -struct _PROGRESSIVE_FRAME_END -{ - UINT16 blockType; - UINT32 blockLen; -}; -typedef struct _PROGRESSIVE_FRAME_END PROGRESSIVE_FRAME_END; - -struct _PROGRESSIVE_TILE_SIMPLE +struct _PROGRESSIVE_BLOCK_TILE_SIMPLE { UINT16 blockType; UINT32 blockLen; @@ -101,9 +119,9 @@ struct _PROGRESSIVE_TILE_SIMPLE BYTE* crData; BYTE* tailData; }; -typedef struct _PROGRESSIVE_TILE_SIMPLE PROGRESSIVE_TILE_SIMPLE; +typedef struct _PROGRESSIVE_BLOCK_TILE_SIMPLE PROGRESSIVE_BLOCK_TILE_SIMPLE; -struct _PROGRESSIVE_TILE_FIRST +struct _PROGRESSIVE_BLOCK_TILE_FIRST { UINT16 blockType; UINT32 blockLen; @@ -124,9 +142,9 @@ struct _PROGRESSIVE_TILE_FIRST BYTE* crData; BYTE* tailData; }; -typedef struct _PROGRESSIVE_TILE_FIRST PROGRESSIVE_TILE_FIRST; +typedef struct _PROGRESSIVE_BLOCK_TILE_FIRST PROGRESSIVE_BLOCK_TILE_FIRST; -struct _PROGRESSIVE_TILE_UPGRADE +struct _PROGRESSIVE_BLOCK_TILE_UPGRADE { UINT16 blockType; UINT32 blockLen; @@ -150,11 +168,103 @@ struct _PROGRESSIVE_TILE_UPGRADE BYTE* crSrlData; BYTE* crRawData; }; -typedef struct _PROGRESSIVE_TILE_UPGRADE PROGRESSIVE_TILE_UPGRADE; +typedef struct _PROGRESSIVE_BLOCK_TILE_UPGRADE PROGRESSIVE_BLOCK_TILE_UPGRADE; + +struct _RFX_PROGRESSIVE_TILE +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE quantIdxY; + BYTE quantIdxCb; + BYTE quantIdxCr; + UINT16 xIdx; + UINT16 yIdx; + + BYTE flags; + BYTE quality; + + UINT16 yLen; + UINT16 cbLen; + UINT16 crLen; + UINT16 tailLen; + BYTE* yData; + BYTE* cbData; + BYTE* crData; + BYTE* tailData; + + UINT16 ySrlLen; + UINT16 yRawLen; + UINT16 cbSrlLen; + UINT16 cbRawLen; + UINT16 crSrlLen; + UINT16 crRawLen; + BYTE* ySrlData; + BYTE* yRawData; + BYTE* cbSrlData; + BYTE* cbRawData; + BYTE* crSrlData; + BYTE* crRawData; +}; +typedef struct _RFX_PROGRESSIVE_TILE RFX_PROGRESSIVE_TILE; + +struct _PROGRESSIVE_BLOCK_REGION +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE tileSize; + UINT16 numRects; + BYTE numQuant; + BYTE numProgQuant; + BYTE flags; + UINT16 numTiles; + UINT32 tileDataSize; + RFX_RECT* rects; + RFX_COMPONENT_CODEC_QUANT* quantVals; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVals; + RFX_PROGRESSIVE_TILE* tiles; +}; +typedef struct _PROGRESSIVE_BLOCK_REGION PROGRESSIVE_BLOCK_REGION; + +struct _PROGRESSIVE_BLOCK_FRAME_BEGIN +{ + UINT16 blockType; + UINT32 blockLen; + + UINT32 frameIndex; + UINT16 regionCount; + PROGRESSIVE_BLOCK_REGION* regions; +}; +typedef struct _PROGRESSIVE_BLOCK_FRAME_BEGIN PROGRESSIVE_BLOCK_FRAME_BEGIN; + +struct _PROGRESSIVE_BLOCK_FRAME_END +{ + UINT16 blockType; + UINT32 blockLen; +}; +typedef struct _PROGRESSIVE_BLOCK_FRAME_END PROGRESSIVE_BLOCK_FRAME_END; struct _PROGRESSIVE_CONTEXT { BOOL Compressor; + + wBufferPool* bufferPool; + + UINT32 cRects; + RFX_RECT* rects; + + UINT32 cTiles; + RFX_PROGRESSIVE_TILE* tiles; + + UINT32 cQuant; + RFX_COMPONENT_CODEC_QUANT* quantVals; + + UINT32 cProgQuant; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVals; + + PROGRESSIVE_BLOCK_REGION region; + RFX_PROGRESSIVE_CODEC_QUANT quantProgValFull; }; typedef struct _PROGRESSIVE_CONTEXT PROGRESSIVE_CONTEXT; diff --git a/include/freerdp/codec/rfx.h b/include/freerdp/codec/rfx.h index 60ada8b79..08480bec2 100644 --- a/include/freerdp/codec/rfx.h +++ b/include/freerdp/codec/rfx.h @@ -146,8 +146,6 @@ struct _RFX_CONTEXT void (*quantization_encode)(INT16* buffer, const UINT32* quantization_values); void (*dwt_2d_decode)(INT16* buffer, INT16* dwt_buffer); void (*dwt_2d_encode)(INT16* buffer, INT16* dwt_buffer); - int (*rlgr_decode)(RLGR_MODE mode, const BYTE* data, int data_size, INT16* buffer, int buffer_size); - int (*rlgr_encode)(RLGR_MODE mode, const INT16* data, int data_size, BYTE* buffer, int buffer_size); /* private definitions */ RFX_CONTEXT_PRIV* priv; @@ -159,6 +157,8 @@ FREERDP_API void rfx_context_free(RFX_CONTEXT* context); FREERDP_API void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format); FREERDP_API void rfx_context_reset(RFX_CONTEXT* context); +FREERDP_API int rfx_rlgr_decode(const BYTE* pSrcData, UINT32 SrcSize, INT16* pDstData, UINT32 DstSize, int mode); + FREERDP_API RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length); FREERDP_API UINT16 rfx_message_get_tile_count(RFX_MESSAGE* message); FREERDP_API RFX_TILE* rfx_message_get_tile(RFX_MESSAGE* message, int index); diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 2dfee8460..24d9493eb 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -28,190 +28,635 @@ #include #include +const char* progressive_get_block_type_string(UINT16 blockType) +{ + switch (blockType) + { + case PROGRESSIVE_WBT_SYNC: + return "PROGRESSIVE_WBT_SYNC"; + break; + + case PROGRESSIVE_WBT_FRAME_BEGIN: + return "PROGRESSIVE_WBT_FRAME_BEGIN"; + break; + + case PROGRESSIVE_WBT_FRAME_END: + return "PROGRESSIVE_WBT_FRAME_END"; + break; + + case PROGRESSIVE_WBT_CONTEXT: + return "PROGRESSIVE_WBT_CONTEXT"; + break; + + case PROGRESSIVE_WBT_REGION: + return "PROGRESSIVE_WBT_REGION"; + break; + + case PROGRESSIVE_WBT_TILE_SIMPLE: + return "PROGRESSIVE_WBT_TILE_SIMPLE"; + break; + + case PROGRESSIVE_WBT_TILE_FIRST: + return "PROGRESSIVE_WBT_TILE_FIRST"; + break; + + case PROGRESSIVE_WBT_TILE_UPGRADE: + return "PROGRESSIVE_WBT_TILE_UPGRADE"; + break; + + default: + return "PROGRESSIVE_WBT_UNKNOWN"; + break; + } + + return "PROGRESSIVE_WBT_UNKNOWN"; +} + +int progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* progressive, + RFX_COMPONENT_CODEC_QUANT* quant, const BYTE* data, int length, INT16* buffer) +{ + int status; + + status = rfx_rlgr_decode(data, length, buffer, 4096, 1); + + if (status < 0) + return status; + + return 1; +} + +int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progressive, RFX_PROGRESSIVE_TILE* tile) +{ + BYTE* pBuffer; + INT16* pSrcDst[3]; + PROGRESSIVE_BLOCK_REGION* region; + RFX_COMPONENT_CODEC_QUANT* quantY; + RFX_COMPONENT_CODEC_QUANT* quantCb; + RFX_COMPONENT_CODEC_QUANT* quantCr; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal; + + printf("ProgressiveTileFirst: quantIdx Y: %d Cb: %d Cr: %d xIdx: %d yIdx: %d flags: %d quality: %d yLen: %d cbLen: %d crLen: %d tailLen: %d\n", + tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx, tile->yIdx, tile->flags, tile->quality, tile->yLen, tile->cbLen, tile->crLen, tile->tailLen); + + region = &(progressive->region); + + if (tile->quantIdxY >= region->numQuant) + return -1; + + quantY = &(region->quantVals[tile->quantIdxY]); + + if (tile->quantIdxCb >= region->numQuant) + return -1; + + quantCb = &(region->quantVals[tile->quantIdxCb]); + + if (tile->quantIdxCr >= region->numQuant) + return -1; + + quantCr = &(region->quantVals[tile->quantIdxCr]); + + if (tile->quality == 0xFF) + { + quantProgVal = &(progressive->quantProgValFull); + } + else + { + if (tile->quality >= region->numProgQuant) + return -1; + + quantProgVal = &(region->quantProgVals[tile->quality]); + } + + pBuffer = (BYTE*) BufferPool_Take(progressive->bufferPool, -1); + pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */ + pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */ + pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */ + + progressive_rfx_decode_component(progressive, quantY, tile->yData, tile->yLen, pSrcDst[0]); /* Y */ + progressive_rfx_decode_component(progressive, quantCb, tile->cbData, tile->cbLen, pSrcDst[1]); /* Cb */ + progressive_rfx_decode_component(progressive, quantCr, tile->crData, tile->crLen, pSrcDst[2]); /* Cr */ + + BufferPool_Return(progressive->bufferPool, pBuffer); + + return 1; +} + +int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progressive, RFX_PROGRESSIVE_TILE* tile) +{ + PROGRESSIVE_BLOCK_REGION* region; + RFX_COMPONENT_CODEC_QUANT* quantY; + RFX_COMPONENT_CODEC_QUANT* quantCb; + RFX_COMPONENT_CODEC_QUANT* quantCr; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal; + + printf("ProgressiveTileUpgrade: quantIdx Y: %d Cb: %d Cr: %d xIdx: %d yIdx: %d quality: %d ySrlLen: %d yRawLen: %d cbSrlLen: %d cbRawLen: %d crSrlLen: %d crRawLen: %d\n", + tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx, tile->yIdx, tile->quality, tile->ySrlLen, tile->yRawLen, tile->cbSrlLen, tile->cbRawLen, tile->crSrlLen, tile->crRawLen); + + region = &(progressive->region); + + if (tile->quantIdxY >= region->numQuant) + return -1; + + quantY = &(region->quantVals[tile->quantIdxY]); + + if (tile->quantIdxCb >= region->numQuant) + return -1; + + quantCb = &(region->quantVals[tile->quantIdxCb]); + + if (tile->quantIdxCr >= region->numQuant) + return -1; + + quantCr = &(region->quantVals[tile->quantIdxCr]); + + if (tile->quality == 0xFF) + { + quantProgVal = &(progressive->quantProgValFull); + } + else + { + if (tile->quality >= region->numProgQuant) + return -1; + + quantProgVal = &(region->quantProgVals[tile->quality]); + } + + return 1; +} + +int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, BYTE* blocks, UINT32 blocksLen) +{ + BYTE* block; + UINT16 index; + UINT32 boffset; + UINT32 count = 0; + UINT32 offset = 0; + RFX_PROGRESSIVE_TILE* tile; + RFX_PROGRESSIVE_TILE* tiles; + PROGRESSIVE_BLOCK_REGION* region; + + region = &(progressive->region); + + tiles = region->tiles; + + while ((blocksLen - offset) >= 6) + { + boffset = 0; + block = &blocks[offset]; + + tile = &tiles[count]; + + tile->blockType = *((UINT16*) &block[boffset + 0]); /* blockType (2 bytes) */ + tile->blockLen = *((UINT32*) &block[boffset + 2]); /* blockLen (4 bytes) */ + boffset += 6; + + printf("%s\n", progressive_get_block_type_string(tile->blockType)); + + if ((blocksLen - offset) < tile->blockLen) + return -1003; + + switch (tile->blockType) + { + case PROGRESSIVE_WBT_TILE_SIMPLE: + + if ((tile->blockLen - boffset) < 16) + return -1022; + + tile->quality = 0xFF; /* simple tiles use no progressive techniques */ + + tile->quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ + tile->quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ + tile->quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ + tile->xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + tile->yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + tile->flags = block[boffset + 7]; /* flags (1 byte) */ + tile->yLen = *((UINT16*) &block[boffset + 8]); /* yLen (2 bytes) */ + tile->cbLen = *((UINT16*) &block[boffset + 10]); /* cbLen (2 bytes) */ + tile->crLen = *((UINT16*) &block[boffset + 12]); /* crLen (2 bytes) */ + tile->tailLen = *((UINT16*) &block[boffset + 14]); /* tailLen (2 bytes) */ + boffset += 16; + + if ((tile->blockLen - boffset) < tile->yLen) + return -1023; + + tile->yData = &block[boffset]; + boffset += tile->yLen; + + if ((tile->blockLen - boffset) < tile->cbLen) + return -1024; + + tile->cbData = &block[boffset]; + boffset += tile->cbLen; + + if ((tile->blockLen - boffset) < tile->crLen) + return -1025; + + tile->crData = &block[boffset]; + boffset += tile->crLen; + + if ((tile->blockLen - boffset) < tile->tailLen) + return -1026; + + tile->tailData = &block[boffset]; + boffset += tile->tailLen; + + break; + + case PROGRESSIVE_WBT_TILE_FIRST: + + if ((tile->blockLen - boffset) < 17) + return -1027; + + tile->quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ + tile->quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ + tile->quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ + tile->xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + tile->yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + tile->flags = block[boffset + 7]; /* flags (1 byte) */ + tile->quality = block[boffset + 8]; /* quality (1 byte) */ + tile->yLen = *((UINT16*) &block[boffset + 9]); /* yLen (2 bytes) */ + tile->cbLen = *((UINT16*) &block[boffset + 11]); /* cbLen (2 bytes) */ + tile->crLen = *((UINT16*) &block[boffset + 13]); /* crLen (2 bytes) */ + tile->tailLen = *((UINT16*) &block[boffset + 15]); /* tailLen (2 bytes) */ + boffset += 17; + + if ((tile->blockLen - boffset) < tile->yLen) + return -1028; + + tile->yData = &block[boffset]; + boffset += tile->yLen; + + if ((tile->blockLen - boffset) < tile->cbLen) + return -1029; + + tile->cbData = &block[boffset]; + boffset += tile->cbLen; + + if ((tile->blockLen - boffset) < tile->crLen) + return -1030; + + tile->crData = &block[boffset]; + boffset += tile->crLen; + + if ((tile->blockLen - boffset) < tile->tailLen) + return -1031; + + tile->tailData = &block[boffset]; + boffset += tile->tailLen; + + break; + + case PROGRESSIVE_WBT_TILE_UPGRADE: + + if ((tile->blockLen - boffset) < 20) + return -1032; + + tile->quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ + tile->quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ + tile->quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ + tile->xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ + tile->yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ + tile->quality = block[boffset + 7]; /* quality (1 byte) */ + tile->ySrlLen = *((UINT16*) &block[boffset + 8]); /* ySrlLen (2 bytes) */ + tile->yRawLen = *((UINT16*) &block[boffset + 10]); /* yRawLen (2 bytes) */ + tile->cbSrlLen = *((UINT16*) &block[boffset + 12]); /* cbSrlLen (2 bytes) */ + tile->cbRawLen = *((UINT16*) &block[boffset + 14]); /* cbRawLen (2 bytes) */ + tile->crSrlLen = *((UINT16*) &block[boffset + 16]); /* crSrlLen (2 bytes) */ + tile->crRawLen = *((UINT16*) &block[boffset + 18]); /* crRawLen (2 bytes) */ + boffset += 20; + + if ((tile->blockLen - boffset) < tile->ySrlLen) + return -1033; + + tile->ySrlData = &block[boffset]; + boffset += tile->ySrlLen; + + if ((tile->blockLen - boffset) < tile->yRawLen) + return -1034; + + tile->yRawData = &block[boffset]; + boffset += tile->yRawLen; + + if ((tile->blockLen - boffset) < tile->cbSrlLen) + return -1035; + + tile->cbSrlData = &block[boffset]; + boffset += tile->cbSrlLen; + + if ((tile->blockLen - boffset) < tile->cbRawLen) + return -1036; + + tile->cbRawData = &block[boffset]; + boffset += tile->cbRawLen; + + if ((tile->blockLen - boffset) < tile->crSrlLen) + return -1037; + + tile->crSrlData = &block[boffset]; + boffset += tile->crSrlLen; + + if ((tile->blockLen - boffset) < tile->crRawLen) + return -1038; + + tile->crRawData = &block[boffset]; + boffset += tile->crRawLen; + + break; + + default: + return -1039; + break; + } + + if (boffset != tile->blockLen) + return -1040; + + offset += tile->blockLen; + count++; + } + + if (offset != blocksLen) + return -1041; + + for (index = 0; index < region->numTiles; index++) + { + tile = &tiles[index]; + + switch (tile->blockType) + { + case PROGRESSIVE_WBT_TILE_SIMPLE: + case PROGRESSIVE_WBT_TILE_FIRST: + progressive_decompress_tile_first(progressive, tile); + break; + + case PROGRESSIVE_WBT_TILE_UPGRADE: + progressive_decompress_tile_upgrade(progressive, tile); + break; + } + } + + return (int) offset; +} + int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight) { + int status; BYTE* block; + BYTE* blocks; + UINT16 index; UINT32 boffset; - UINT32 ctxId; - UINT32 flags; - UINT32 tileSize; - UINT32 magic; - UINT32 version; UINT16 blockType; UINT32 blockLen; + UINT32 blocksLen; + UINT32 count = 0; UINT32 offset = 0; - UINT32 frameIndex; - UINT32 regionCount; - PROGRESSIVE_REGION region; - PROGRESSIVE_TILE_SIMPLE simple; - PROGRESSIVE_TILE_FIRST first; - PROGRESSIVE_TILE_UPGRADE upgrade; + RFX_RECT* rect = NULL; + PROGRESSIVE_BLOCK_SYNC sync; + PROGRESSIVE_BLOCK_REGION* region; + PROGRESSIVE_BLOCK_CONTEXT context; + PROGRESSIVE_BLOCK_FRAME_BEGIN frameBegin; + PROGRESSIVE_BLOCK_FRAME_END frameEnd; + RFX_COMPONENT_CODEC_QUANT* quantVal; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal; - printf("ProgressiveDecompress\n"); + blocks = pSrcData; + blocksLen = SrcSize; - while ((SrcSize - offset) > 6) + region = &(progressive->region); + + while ((blocksLen - offset) >= 6) { boffset = 0; - block = &pSrcData[offset]; + block = &blocks[offset]; - blockType = *((UINT16*) &block[boffset]); /* blockType (2 bytes) */ + blockType = *((UINT16*) &block[boffset + 0]); /* blockType (2 bytes) */ blockLen = *((UINT32*) &block[boffset + 2]); /* blockLen (4 bytes) */ boffset += 6; + printf("%s\n", progressive_get_block_type_string(blockType)); + + if ((blocksLen - offset) < blockLen) + return -1003; + switch (blockType) { case PROGRESSIVE_WBT_SYNC: - if (blockLen != 12) - return -1; + sync.blockType = blockType; + sync.blockLen = blockLen; - magic = (UINT32) *((UINT32*) &block[boffset]); /* magic (4 bytes) */ - version = (UINT32) *((UINT16*) &block[boffset + 4]); /* version (2 bytes) */ + if ((blockLen - boffset) != 6) + return -1004; + + sync.magic = (UINT32) *((UINT32*) &block[boffset + 0]); /* magic (4 bytes) */ + sync.version = (UINT32) *((UINT16*) &block[boffset + 4]); /* version (2 bytes) */ boffset += 6; + if (sync.magic != 0xCACCACCA) + return -1005; + + if (sync.version != 0x0100) + return -1006; + break; case PROGRESSIVE_WBT_FRAME_BEGIN: - frameIndex = (UINT32) *((UINT32*) &block[boffset]); /* frameIndex (4 bytes) */ - regionCount = (UINT32) *((UINT16*) &block[boffset + 4]); /* regionCount (2 bytes) */ + frameBegin.blockType = blockType; + frameBegin.blockLen = blockLen; + + if ((blockLen - boffset) < 6) + return -1007; + + frameBegin.frameIndex = (UINT32) *((UINT32*) &block[boffset + 0]); /* frameIndex (4 bytes) */ + frameBegin.regionCount = (UINT32) *((UINT16*) &block[boffset + 4]); /* regionCount (2 bytes) */ boffset += 6; + /** + * If the number of elements specified by the regionCount field is + * larger than the actual number of elements in the regions field, + * the decoder SHOULD ignore this inconsistency. + */ + break; case PROGRESSIVE_WBT_FRAME_END: - if (blockLen != 6) - return -1; + frameEnd.blockType = blockType; + frameEnd.blockLen = blockLen; + + if ((blockLen - boffset) != 0) + return -1008; break; case PROGRESSIVE_WBT_CONTEXT: - if (blockLen != 10) - return -1; + context.blockType = blockType; + context.blockLen = blockLen; - ctxId = (UINT32) block[boffset]; /* ctxId (1 byte) */ - tileSize = (UINT32) *((UINT16*) &block[boffset + 1]); /* tileSize (2 bytes) */ - flags = (UINT32) block[boffset + 3]; /* flags (1 byte) */ + if ((blockLen - boffset) != 4) + return -1009; + + context.ctxId = block[boffset + 0]; /* ctxId (1 byte) */ + context.tileSize = *((UINT16*) &block[boffset + 1]); /* tileSize (2 bytes) */ + context.flags = block[boffset + 3]; /* flags (1 byte) */ boffset += 4; - if (tileSize != 64) - return -1; + if (context.tileSize != 64) + return -1010; break; case PROGRESSIVE_WBT_REGION: - region.tileSize = block[boffset]; /* tileSize (1 byte) */ - region.numRects = *((UINT16*) &block[boffset + 1]); /* numRects (2 bytes) */ - region.numQuant = block[boffset + 3]; /* numQuant (1 byte) */ - region.numProgQuant = block[boffset + 4]; /* numProgQuant (1 byte) */ - region.flags = block[boffset + 5]; /* flags (1 byte) */ - region.numTiles = *((UINT16*) &block[boffset + 6]); /* numTiles (2 bytes) */ - region.tileDataSize = *((UINT32*) &block[boffset + 8]); /* tileDataSize (4 bytes) */ + region->blockType = blockType; + region->blockLen = blockLen; + + if ((blockLen - boffset) < 12) + return -1011; + + region->tileSize = block[boffset + 0]; /* tileSize (1 byte) */ + region->numRects = *((UINT16*) &block[boffset + 1]); /* numRects (2 bytes) */ + region->numQuant = block[boffset + 3]; /* numQuant (1 byte) */ + region->numProgQuant = block[boffset + 4]; /* numProgQuant (1 byte) */ + region->flags = block[boffset + 5]; /* flags (1 byte) */ + region->numTiles = *((UINT16*) &block[boffset + 6]); /* numTiles (2 bytes) */ + region->tileDataSize = *((UINT32*) &block[boffset + 8]); /* tileDataSize (4 bytes) */ boffset += 12; - break; + if (region->tileSize != 64) + return -1012; - case PROGRESSIVE_WBT_TILE_SIMPLE: + if (region->numRects < 1) + return -1013; - simple.quantIdxY = block[boffset]; /* quantIdxY (1 byte) */ - simple.quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ - simple.quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ - simple.xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ - simple.yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ - simple.flags = block[boffset + 7]; /* flags (1 byte) */ - simple.yLen = *((UINT16*) &block[boffset + 8]); /* yLen (2 bytes) */ - simple.cbLen = *((UINT16*) &block[boffset + 10]); /* cbLen (2 bytes) */ - simple.crLen = *((UINT16*) &block[boffset + 12]); /* crLen (2 bytes) */ - simple.tailLen = *((UINT16*) &block[boffset + 14]); /* tailLen (2 bytes) */ - boffset += 16; + if (region->numQuant > 7) + return -1014; - simple.yData = &block[boffset]; - boffset += simple.yLen; + if ((blockLen - boffset) < (region->numRects * 8)) + return -1015; - simple.cbData = &block[boffset]; - boffset += simple.cbLen; + if (region->numRects > progressive->cRects) + { + progressive->rects = (RFX_RECT*) realloc(progressive->rects, region->numRects * sizeof(RFX_RECT)); + progressive->cRects = region->numRects; + } - simple.crData = &block[boffset]; - boffset += simple.crLen; + region->rects = progressive->rects; - simple.tailData = &block[boffset]; - boffset += simple.tailLen; + if (!region->rects) + return -1016; + + for (index = 0; index < region->numRects; index++) + { + rect = &(region->rects[index]); + rect->x = *((UINT16*) &block[boffset + 0]); + rect->y = *((UINT16*) &block[boffset + 2]); + rect->width = *((UINT16*) &block[boffset + 4]); + rect->height = *((UINT16*) &block[boffset + 6]); + boffset += 8; + } + + if ((blockLen - boffset) < (region->numQuant * 5)) + return -1017; + + if (region->numQuant > progressive->cQuant) + { + progressive->quantVals = (RFX_COMPONENT_CODEC_QUANT*) realloc(progressive->quantVals, + region->numQuant * sizeof(RFX_COMPONENT_CODEC_QUANT)); + progressive->cQuant = region->numQuant; + } + + region->quantVals = progressive->quantVals; + + if (!region->quantVals) + return -1018; + + for (index = 0; index < region->numQuant; index++) + { + quantVal = &(region->quantVals[index]); + quantVal->LL3 = block[boffset + 0] & 0x0F; + quantVal->HL3 = block[boffset + 0] >> 4; + quantVal->LH3 = block[boffset + 1] & 0x0F; + quantVal->HH3 = block[boffset + 1] >> 4; + quantVal->HL2 = block[boffset + 2] & 0x0F; + quantVal->LH2 = block[boffset + 2] >> 4; + quantVal->HH2 = block[boffset + 3] & 0x0F; + quantVal->HL1 = block[boffset + 3] >> 4; + quantVal->LH1 = block[boffset + 4] & 0x0F; + quantVal->HH1 = block[boffset + 4] >> 4; + boffset += 5; + } + + if ((blockLen - boffset) < (region->numProgQuant * 16)) + return -1019; + + if (region->numProgQuant > progressive->cProgQuant) + { + progressive->quantProgVals = (RFX_PROGRESSIVE_CODEC_QUANT*) realloc(progressive->quantProgVals, + region->numProgQuant * sizeof(RFX_PROGRESSIVE_CODEC_QUANT)); + progressive->cProgQuant = region->numProgQuant; + } + + region->quantProgVals = progressive->quantProgVals; + + if (!region->quantProgVals) + return -1020; + + for (index = 0; index < region->numProgQuant; index++) + { + quantProgVal = &(region->quantProgVals[index]); + quantProgVal->quality = block[boffset + 0]; + CopyMemory(quantProgVal->yQuantValues, &block[boffset + 1], 5); + CopyMemory(quantProgVal->cbQuantValues, &block[boffset + 6], 5); + CopyMemory(quantProgVal->crQuantValues, &block[boffset + 11], 5); + boffset += 16; + } + + if ((blockLen - boffset) < region->tileDataSize) + return -1021; + + if (region->numTiles > progressive->cTiles) + { + progressive->tiles = (RFX_PROGRESSIVE_TILE*) realloc(progressive->tiles, + region->numTiles * sizeof(RFX_PROGRESSIVE_TILE)); + progressive->cTiles = region->numTiles; + } + + region->tiles = progressive->tiles; + + if (!region->tiles) + return -1; + + printf("numRects: %d numTiles: %d numQuant: %d numProgQuant: %d\n", + region->numRects, region->numTiles, region->numQuant, region->numProgQuant); + + status = progressive_process_tiles(progressive, &block[boffset], region->tileDataSize); + + if (status < 0) + return status; + + boffset += (UINT32) status; break; - case PROGRESSIVE_WBT_TILE_PROGRESSIVE_FIRST: - - first.quantIdxY = block[boffset]; /* quantIdxY (1 byte) */ - first.quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ - first.quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ - first.xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ - first.yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ - first.flags = block[boffset + 7]; /* flags (1 byte) */ - first.quality = block[boffset + 8]; /* quality (1 byte) */ - first.yLen = *((UINT16*) &block[boffset + 9]); /* yLen (2 bytes) */ - first.cbLen = *((UINT16*) &block[boffset + 11]); /* cbLen (2 bytes) */ - first.crLen = *((UINT16*) &block[boffset + 13]); /* crLen (2 bytes) */ - first.tailLen = *((UINT16*) &block[boffset + 15]); /* tailLen (2 bytes) */ - boffset += 17; - - first.yData = &block[boffset]; - boffset += first.yLen; - - first.cbData = &block[boffset]; - boffset += first.cbLen; - - first.crData = &block[boffset]; - boffset += first.crLen; - - first.tailData = &block[boffset]; - boffset += first.tailLen; - - break; - - case PROGRESSIVE_WBT_TILE_PROGRESSIVE_UPGRADE: - - upgrade.quantIdxY = block[boffset]; /* quantIdxY (1 byte) */ - upgrade.quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ - upgrade.quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ - upgrade.xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ - upgrade.yIdx = *((UINT16*) &block[boffset + 5]); /* yIdx (2 bytes) */ - upgrade.quality = block[boffset + 7]; /* quality (1 byte) */ - upgrade.ySrlLen = *((UINT16*) &block[boffset + 8]); /* ySrlLen (2 bytes) */ - upgrade.yRawLen = *((UINT16*) &block[boffset + 10]); /* yRawLen (2 bytes) */ - upgrade.cbSrlLen = *((UINT16*) &block[boffset + 12]); /* cbSrlLen (2 bytes) */ - upgrade.cbRawLen = *((UINT16*) &block[boffset + 14]); /* cbRawLen (2 bytes) */ - upgrade.crSrlLen = *((UINT16*) &block[boffset + 16]); /* crSrlLen (2 bytes) */ - upgrade.crRawLen = *((UINT16*) &block[boffset + 18]); /* crRawLen (2 bytes) */ - boffset += 18; - - upgrade.ySrlData = &block[boffset]; - boffset += upgrade.ySrlLen; - - upgrade.yRawData = &block[boffset]; - boffset += upgrade.yRawLen; - - upgrade.cbSrlData = &block[boffset]; - boffset += upgrade.cbSrlLen; - - upgrade.cbRawData = &block[boffset]; - boffset += upgrade.cbRawLen; - - upgrade.crSrlData = &block[boffset]; - boffset += upgrade.crSrlLen; - - upgrade.crRawData = &block[boffset]; - boffset += upgrade.crRawLen; - + default: + return -1039; break; } + if (boffset != blockLen) + return -1040; + offset += blockLen; + count++; } + if (offset != blocksLen) + return -1041; + return 1; } @@ -234,6 +679,37 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) if (progressive) { progressive->Compressor = Compressor; + + progressive->bufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16); + + progressive->cRects = 64; + progressive->rects = (RFX_RECT*) malloc(progressive->cRects * sizeof(RFX_RECT)); + + if (!progressive->rects) + return NULL; + + progressive->cTiles = 64; + progressive->tiles = (RFX_PROGRESSIVE_TILE*) malloc(progressive->cTiles * sizeof(RFX_PROGRESSIVE_TILE)); + + if (!progressive->tiles) + return NULL; + + progressive->cQuant = 8; + progressive->quantVals = (RFX_COMPONENT_CODEC_QUANT*) malloc(progressive->cQuant * sizeof(RFX_COMPONENT_CODEC_QUANT)); + + if (!progressive->quantVals) + return NULL; + + progressive->cProgQuant = 8; + progressive->quantProgVals = (RFX_PROGRESSIVE_CODEC_QUANT*) malloc(progressive->cProgQuant * sizeof(RFX_PROGRESSIVE_CODEC_QUANT)); + + if (!progressive->quantProgVals) + return NULL; + + ZeroMemory(&(progressive->quantProgValFull), sizeof(RFX_PROGRESSIVE_CODEC_QUANT)); + progressive->quantProgValFull.quality = 100; + + progressive_context_reset(progressive); } return progressive; @@ -244,6 +720,13 @@ void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) if (!progressive) return; + BufferPool_Free(progressive->bufferPool); + + free(progressive->rects); + free(progressive->tiles); + free(progressive->quantVals); + free(progressive->quantProgVals); + free(progressive); } diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index ecfd09f8e..3f23c6818 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -330,8 +330,6 @@ RFX_CONTEXT* rfx_context_new(BOOL encoder) context->quantization_encode = rfx_quantization_encode; context->dwt_2d_decode = rfx_dwt_2d_decode; context->dwt_2d_encode = rfx_dwt_2d_encode; - context->rlgr_decode = rfx_rlgr_decode; - context->rlgr_encode = rfx_rlgr_encode; RFX_INIT_SIMD(context); diff --git a/libfreerdp/codec/rfx_decode.c b/libfreerdp/codec/rfx_decode.c index 3d027a393..d3baf5462 100644 --- a/libfreerdp/codec/rfx_decode.c +++ b/libfreerdp/codec/rfx_decode.c @@ -103,7 +103,7 @@ static void rfx_decode_component(RFX_CONTEXT* context, const UINT32* quantizatio PROFILER_ENTER(context->priv->prof_rfx_decode_component); PROFILER_ENTER(context->priv->prof_rfx_rlgr_decode); - context->rlgr_decode(context->mode, data, size, buffer, 4096); + rfx_rlgr_decode(data, size, buffer, 4096, (context->mode == RLGR1) ? 1 : 3); PROFILER_EXIT(context->priv->prof_rfx_rlgr_decode); PROFILER_ENTER(context->priv->prof_rfx_differential_decode); diff --git a/libfreerdp/codec/rfx_encode.c b/libfreerdp/codec/rfx_encode.c index 5dd10e29f..f929846cf 100644 --- a/libfreerdp/codec/rfx_encode.c +++ b/libfreerdp/codec/rfx_encode.c @@ -209,7 +209,7 @@ static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantizatio PROFILER_EXIT(context->priv->prof_rfx_differential_encode); PROFILER_ENTER(context->priv->prof_rfx_rlgr_encode); - *size = context->rlgr_encode(context->mode, data, 4096, buffer, buffer_size); + *size = rfx_rlgr_encode(context->mode, data, 4096, buffer, buffer_size); PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode); PROFILER_EXIT(context->priv->prof_rfx_encode_component); diff --git a/libfreerdp/codec/rfx_rlgr.c b/libfreerdp/codec/rfx_rlgr.c index e6a1c2e1a..1571dec20 100644 --- a/libfreerdp/codec/rfx_rlgr.c +++ b/libfreerdp/codec/rfx_rlgr.c @@ -31,43 +31,20 @@ #include #include +#include +#include #include "rfx_bitstream.h" #include "rfx_rlgr.h" -/* Constants used within the RLGR1/RLGR3 algorithm */ -#define KPMAX (80) /* max value for kp or krp */ -#define LSGR (3) /* shift count to convert kp to k */ -#define UP_GR (4) /* increase in kp after a zero run in RL mode */ -#define DN_GR (6) /* decrease in kp after a nonzero symbol in RL mode */ -#define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */ -#define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */ - -/* Gets (returns) the next nBits from the bitstream */ -#define GetBits(nBits, r) rfx_bitstream_get_bits(bs, nBits, r) - -/* From current output pointer, write "value", check and update buffer_size */ -#define WriteValue(value) \ -{ \ - if (buffer_size > 0) \ - *dst++ = (value); \ - buffer_size--; \ -} - -/* From current output pointer, write next nZeroes terms with value 0, check and update buffer_size */ -#define WriteZeroes(nZeroes) \ -{ \ - int nZeroesWritten = (nZeroes); \ - if (nZeroesWritten > buffer_size) \ - nZeroesWritten = buffer_size; \ - if (nZeroesWritten > 0) \ - { \ - memset(dst, 0, nZeroesWritten * sizeof(INT16)); \ - dst += nZeroesWritten; \ - } \ - buffer_size -= (nZeroes); \ -} +/* Constants used in RLGR1/RLGR3 algorithm */ +#define KPMAX (80) /* max value for kp or krp */ +#define LSGR (3) /* shift count to convert kp to k */ +#define UP_GR (4) /* increase in kp after a zero run in RL mode */ +#define DN_GR (6) /* decrease in kp after a nonzero symbol in RL mode */ +#define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */ +#define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */ /* Returns the least number of bits required to represent a given value */ #define GetMinBits(_val, _nbits) \ @@ -81,9 +58,6 @@ } \ } -/* Converts from (2 * magnitude - sign) to integer */ -#define GetIntFrom2MagSign(twoMs) (((twoMs) & 1) ? -1 * (INT16)(((twoMs) + 1) >> 1) : (INT16)((twoMs) >> 1)) - /* * Update the passed parameter and clamp it to the range [0, KPMAX] * Return the value of parameter right-shifted by LSGR @@ -98,147 +72,420 @@ _k = (_param >> LSGR); \ } -/* Outputs the Golomb/Rice encoding of a non-negative integer */ -#define GetGRCode(krp, kr, vk, _mag) \ - vk = 0; \ - _mag = 0; \ - /* chew up/count leading 1s and escape 0 */ \ - do { \ - GetBits(1, r); \ - if (r == 1) \ - vk++; \ - else \ - break; \ - } while (1); \ - /* get next *kr bits, and combine with leading 1s */ \ - GetBits(*kr, _mag); \ - _mag |= (vk << *kr); \ - /* adjust krp and kr based on vk */ \ - if (!vk) { \ - UpdateParam(*krp, -2, *kr); \ - } \ - else if (vk != 1) { \ - UpdateParam(*krp, vk, *kr); /* at 1, no change! */ \ - } - -int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* data, int data_size, INT16* buffer, int buffer_size) +int rfx_rlgr_decode(const BYTE* pSrcData, UINT32 SrcSize, INT16* pDstData, UINT32 DstSize, int mode) { - int k; - int kp; - int kr; - int krp; - UINT16 r; - INT16* dst; - RFX_BITSTREAM* bs; - int vk; - UINT16 mag16; + int run; + int cnt; + int size; + int nbits; + int offset; + INT16 mag; + int k, kp; + int kr, krp; + UINT16 code; + UINT32 sign; + UINT32 nIdx; + UINT32 val1; + UINT32 val2; + INT16* pOutput; + wBitStream* bs; + wBitStream s_bs; - bs = (RFX_BITSTREAM*) malloc(sizeof(RFX_BITSTREAM)); - ZeroMemory(bs, sizeof(RFX_BITSTREAM)); - - rfx_bitstream_attach(bs, data, data_size); - dst = buffer; - - /* initialize the parameters */ k = 1; kp = k << LSGR; + kr = 1; krp = kr << LSGR; - while (!rfx_bitstream_eos(bs) && buffer_size > 0) + if ((mode != 1) && (mode != 3)) + mode = 1; + + if (!pSrcData || !SrcSize) + return -1; + + if (!pDstData || !DstSize) + return -1; + + pOutput = pDstData; + + bs = &s_bs; + + BitStream_Attach(bs, pSrcData, SrcSize); + BitStream_Fetch(bs); + + while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize)) { - int run; if (k) { - int mag; - UINT32 sign; + /* Run-Length (RL) Mode */ - /* RL MODE */ - while (!rfx_bitstream_eos(bs)) + run = 0; + + /* count number of leading 0s */ + + cnt = __lzcnt(bs->accumulator); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) { - GetBits(1, r); - if (r) - break; - /* we have an RL escape "0", which translates to a run (1<accumulator); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; } - /* next k bits will contain remaining run or zeros */ - GetBits(k, run); - WriteZeroes(run); + BitStream_Shift(bs, (vk % 32)); - /* get nonzero value, starting with sign bit and then GRCode for magnitude -1 */ - GetBits(1, sign); + if (BitStream_GetRemainingLength(bs) < 1) + break; - /* magnitude - 1 was coded (because it was nonzero) */ - GetGRCode(&krp, &kr, vk, mag16) - mag = (int) (mag16 + 1); + BitStream_Shift(bs, 1); - WriteValue(sign ? -mag : mag); - UpdateParam(kp, -DN_GR, k); /* lower k and kp because of nonzero term */ + while (vk--) + { + run += (1 << k); /* add (1 << k) to run length */ + + /* update k, kp params */ + + kp += UP_GR; + + if (kp > KPMAX) + kp = KPMAX; + + k = kp >> LSGR; + } + + /* next k bits contain run length remainder */ + + if (BitStream_GetRemainingLength(bs) < k) + break; + + bs->mask = ((1 << k) - 1); + run += ((bs->accumulator >> (32 - k)) & bs->mask); + BitStream_Shift(bs, k); + + /* read sign bit */ + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + sign = (bs->accumulator & 0x80000000) ? 1 : 0; + BitStream_Shift(bs, 1); + + /* count number of leading 1s */ + + cnt = __lzcnt(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) + { + BitStream_Shift32(bs); + + cnt = __lzcnt(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; + } + + BitStream_Shift(bs, (vk % 32)); + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + BitStream_Shift(bs, 1); + + /* next kr bits contain code remainder */ + + if (BitStream_GetRemainingLength(bs) < kr) + break; + + bs->mask = ((1 << kr) - 1); + code = (UINT16) ((bs->accumulator >> (32 - kr)) & bs->mask); + BitStream_Shift(bs, kr); + + /* add (vk << kr) to code */ + + code |= (vk << kr); + + if (!vk) + { + /* update kr, krp params */ + + krp -= 2; + + if (krp < 0) + krp = 0; + + kr = krp >> LSGR; + } + else if (vk != 1) + { + /* update kr, krp params */ + + krp += vk; + + if (krp > KPMAX) + krp = KPMAX; + + kr = krp >> LSGR; + } + + /* update k, kp params */ + + kp -= DN_GR; + + if (kp < 0) + kp = 0; + + k = kp >> LSGR; + + /* compute magnitude from code */ + + if (sign) + mag = ((INT16) (code + 1)) * -1; + else + mag = (INT16) (code + 1); + + /* write to output stream */ + + offset = (int) (pOutput - pDstData); + size = run; + + if ((offset + size) > DstSize) + size = DstSize - offset; + + if (size) + { + ZeroMemory(pOutput, size * sizeof(INT16)); + pOutput += size; + } + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; + } } else { - UINT32 mag; - UINT32 nIdx; - UINT32 val1; - UINT32 val2; + /* Golomb-Rice (GR) Mode */ - /* GR (GOLOMB-RICE) MODE */ - GetGRCode(&krp, &kr, vk, mag16) /* values coded are 2 * magnitude - sign */ - mag = (UINT32) mag16; + /* count number of leading 1s */ - if (mode == RLGR1) + cnt = __lzcnt(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) { - if (!mag) + BitStream_Shift32(bs); + + cnt = __lzcnt(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; + } + + BitStream_Shift(bs, (vk % 32)); + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + BitStream_Shift(bs, 1); + + /* next kr bits contain code remainder */ + + if (BitStream_GetRemainingLength(bs) < kr) + break; + + bs->mask = ((1 << kr) - 1); + code = (UINT16) ((bs->accumulator >> (32 - kr)) & bs->mask); + BitStream_Shift(bs, kr); + + /* add (vk << kr) to code */ + + code |= (vk << kr); + + if (!vk) + { + /* update kr, krp params */ + + krp -= 2; + + if (krp < 0) + krp = 0; + + kr = krp >> LSGR; + } + else if (vk != 1) + { + /* update kr, krp params */ + + krp += vk; + + if (krp > KPMAX) + krp = KPMAX; + + kr = krp >> LSGR; + } + + if (mode == 1) /* RLGR1 */ + { + if (!code) { - WriteValue(0); - UpdateParam(kp, UQ_GR, k); /* raise k and kp due to zero */ + /* update k, kp params */ + + kp += UQ_GR; + + if (kp > KPMAX) + kp = KPMAX; + + k = kp >> LSGR; + + mag = 0; } else { - WriteValue(GetIntFrom2MagSign(mag)); - UpdateParam(kp, -DQ_GR, k); /* lower k and kp due to nonzero */ + /* update k, kp params */ + + kp -= DQ_GR; + + if (kp < 0) + kp = 0; + + k = kp >> LSGR; + + /* + * code = 2 * mag - sign + * sign + code = 2 * mag + */ + + if (code & 1) + mag = ((INT16) ((code + 1) >> 1)) * -1; + else + mag = (INT16) (code >> 1); + } + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; } } - else /* mode == RLGR3 */ + else if (mode == 3) /* RLGR3 */ { - /* - * In GR mode FOR RLGR3, we have encoded the - * sum of two (2 * mag - sign) values - */ + nIdx = 0; - /* maximum possible bits for first term */ - GetMinBits(mag, nIdx); + if (code) + { + mag = (UINT32) code; + nIdx = 32 - __lzcnt(mag); + } - /* decode val1 is first term's (2 * mag - sign) value */ - GetBits(nIdx, val1); + if (BitStream_GetRemainingLength(bs) < nIdx) + break; - /* val2 is second term's (2 * mag - sign) value */ - val2 = mag - val1; + bs->mask = ((1 << nIdx) - 1); + val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask); + BitStream_Shift(bs, nIdx); + + val2 = code - val1; if (val1 && val2) { - /* raise k and kp if both terms nonzero */ - UpdateParam(kp, -2 * DQ_GR, k); + /* update k, kp params */ + + kp -= (2 * DQ_GR); + + if (kp < 0) + kp = 0; + + k = kp >> LSGR; } else if (!val1 && !val2) { - /* lower k and kp if both terms zero */ - UpdateParam(kp, 2 * UQ_GR, k); + /* update k, kp params */ + + kp += (2 * UQ_GR); + + if (kp > KPMAX) + kp = KPMAX; + + k = kp >> LSGR; } - WriteValue(GetIntFrom2MagSign(val1)); - WriteValue(GetIntFrom2MagSign(val2)); + if (val1 & 1) + mag = ((INT16) ((val1 + 1) >> 1)) * -1; + else + mag = (INT16) (val1 >> 1); + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; + } + + if (val2 & 1) + mag = ((INT16) ((val2 + 1) >> 1)) * -1; + else + mag = (INT16) (val2 >> 1); + + if ((pOutput - pDstData) < DstSize) + { + *pOutput = mag; + pOutput++; + } } } } - free(bs); + offset = (int) (pOutput - pDstData); - return (dst - buffer); + if (offset < DstSize) + { + size = DstSize - offset; + ZeroMemory(pOutput, size * 2); + pOutput += size; + } + + offset = (int) (pOutput - pDstData); + + if (offset != DstSize) + return -1; + + return 1; } /* Returns the next coefficient (a signed int) to encode, from the input stream */ diff --git a/libfreerdp/codec/rfx_rlgr.h b/libfreerdp/codec/rfx_rlgr.h index 07fa895f6..25b16cf43 100644 --- a/libfreerdp/codec/rfx_rlgr.h +++ b/libfreerdp/codec/rfx_rlgr.h @@ -22,7 +22,6 @@ #include -int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* data, int data_size, INT16* buffer, int buffer_size); int rfx_rlgr_encode(RLGR_MODE mode, const INT16* data, int data_size, BYTE* buffer, int buffer_size); #endif /* __RFX_RLGR_H */ diff --git a/winpr/include/winpr/bitstream.h b/winpr/include/winpr/bitstream.h index b77a1dc97..c67d58e38 100644 --- a/winpr/include/winpr/bitstream.h +++ b/winpr/include/winpr/bitstream.h @@ -27,11 +27,11 @@ struct _wBitStream { - BYTE* buffer; + const BYTE* buffer; BYTE* pointer; - DWORD position; - DWORD length; - DWORD capacity; + int position; + int length; + int capacity; UINT32 mask; UINT32 offset; UINT32 prefetch; @@ -83,28 +83,38 @@ extern "C" { } while(0) #define BitStream_Shift(_bs, _nbits) do { \ - _bs->accumulator <<= _nbits; \ - _bs->position += _nbits; \ - _bs->offset += _nbits; \ - if (_bs->offset < 32) { \ - _bs->mask = ((1 << _nbits) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ - _bs->prefetch <<= _nbits; \ - } else { \ - _bs->mask = ((1 << _nbits) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ - _bs->prefetch <<= _nbits; \ - _bs->offset -= 32; \ - _bs->pointer += 4; \ - BitStream_Prefetch(_bs); \ - if (_bs->offset) { \ - _bs->mask = ((1 << _bs->offset) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _bs->offset)) & _bs->mask); \ - _bs->prefetch <<= _bs->offset; \ + if (_nbits == 0) { \ + } else if ((_nbits > 0) && (_nbits < 32)) { \ + _bs->accumulator <<= _nbits; \ + _bs->position += _nbits; \ + _bs->offset += _nbits; \ + if (_bs->offset < 32) { \ + _bs->mask = ((1 << _nbits) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ + _bs->prefetch <<= _nbits; \ + } else { \ + _bs->mask = ((1 << _nbits) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ + _bs->prefetch <<= _nbits; \ + _bs->offset -= 32; \ + _bs->pointer += 4; \ + BitStream_Prefetch(_bs); \ + if (_bs->offset) { \ + _bs->mask = ((1 << _bs->offset) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _bs->offset)) & _bs->mask); \ + _bs->prefetch <<= _bs->offset; \ + } \ } \ + } else { \ + fprintf(stderr, "warning: BitStream_Shift(%d)\n", _nbits); \ } \ } while(0) +#define BitStream_Shift32(_bs) do { \ + BitStream_Shift(_bs, 16); \ + BitStream_Shift(_bs, 16); \ +} while(0) + #define BitStream_Write_Bits(_bs, _bits, _nbits) do { \ _bs->position += _nbits; \ _bs->offset += _nbits; \ @@ -124,10 +134,13 @@ extern "C" { } \ } while(0) +#define BitStream_GetRemainingLength(_bs) \ + (_bs->length - _bs->position) + WINPR_API void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags); WINPR_API UINT32 ReverseBits32(UINT32 bits, UINT32 nbits); -WINPR_API void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity); +WINPR_API void BitStream_Attach(wBitStream* bs, const BYTE* buffer, UINT32 capacity); WINPR_API wBitStream* BitStream_New(); WINPR_API void BitStream_Free(wBitStream* bs); diff --git a/winpr/include/winpr/crt.h b/winpr/include/winpr/crt.h index 6da3f4b16..ed136a2a0 100644 --- a/winpr/include/winpr/crt.h +++ b/winpr/include/winpr/crt.h @@ -82,6 +82,55 @@ static INLINE UINT64 _rotr64(UINT64 value, int shift) { #endif +/** + * __lzcnt16, __lzcnt, __lzcnt64: + * http://msdn.microsoft.com/en-us/library/bb384809/ + */ + +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) + +/** + * __lzcnt16, __lzcnt, __lzcnt64: + * http://msdn.microsoft.com/en-us/library/bb384809/ + * + * Beware: the result of __builtin_clz(0) is undefined + */ + +static INLINE UINT32 __lzcnt(UINT32 _val32) { + return _val32 ? ((UINT32) __builtin_clz(_val32)) : 32; +} + +static INLINE UINT16 __lzcnt16(UINT16 _val16) { + return _val16 ? ((UINT16) (__builtin_clz((UINT32) _val16) - 16)) : 16; +} + +static INLINE UINT64 __lzcnt64(UINT64 _val64) { + return _val64 ? ((UINT64) __builtin_clzll(_val64)) : 64; +} + +#else + +static INLINE UINT32 __lzcnt(UINT32 x) { + unsigned y; + int n = 32; + y = x >> 16; if (y != 0) { n = n - 16; x = y; } + y = x >> 8; if (y != 0) { n = n - 8; x = y; } + y = x >> 4; if (y != 0) { n = n - 4; x = y; } + y = x >> 2; if (y != 0) { n = n - 2; x = y; } + y = x >> 1; if (y != 0) return n - 2; + return n - x; +} + +static INLINE UINT16 __lzcnt16(UINT16 x) { + return ((UINT16) __lzcnt((UINT32) x)); +} + +static INLINE UINT64 __lzcnt64(UINT64 x) { + return 0; /* TODO */ +} + +#endif + #endif #ifndef _WIN32 diff --git a/winpr/libwinpr/crt/test/CMakeLists.txt b/winpr/libwinpr/crt/test/CMakeLists.txt index 4f1f9d3fd..4bccde151 100644 --- a/winpr/libwinpr/crt/test/CMakeLists.txt +++ b/winpr/libwinpr/crt/test/CMakeLists.txt @@ -8,6 +8,7 @@ set(${MODULE_PREFIX}_TESTS TestTypes.c TestAlignment.c TestString.c + TestIntrinsics.c TestUnicodeConversion.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/crt/test/TestIntrinsics.c b/winpr/libwinpr/crt/test/TestIntrinsics.c new file mode 100644 index 000000000..bb1f07b05 --- /dev/null +++ b/winpr/libwinpr/crt/test/TestIntrinsics.c @@ -0,0 +1,109 @@ + +#include +#include +#include + +int test_lzcnt() +{ + if (__lzcnt(0x0) != 32) { + fprintf(stderr, "__lzcnt(0x0) != 32\n"); + return -1; + } + + if (__lzcnt(0x1) != 31) { + fprintf(stderr, "__lzcnt(0x1) != 31\n"); + return -1; + } + + if (__lzcnt(0xFF) != 24) { + fprintf(stderr, "__lzcnt(0xFF) != 24\n"); + return -1; + } + + if (__lzcnt(0xFFFF) != 16) { + fprintf(stderr, "__lzcnt(0xFFFF) != 16\n"); + return -1; + } + + if (__lzcnt(0xFFFFFF) != 8) { + fprintf(stderr, "__lzcnt(0xFFFFFF) != 8\n"); + return -1; + } + + if (__lzcnt(0xFFFFFFFF) != 0) { + fprintf(stderr, "__lzcnt(0xFFFFFFFF) != 0\n"); + return -1; + } + + return 1; +} + +int test_lzcnt16() +{ + if (__lzcnt16(0x0) != 16) { + fprintf(stderr, "__lzcnt16(0x0) != 16\n"); + return -1; + } + + if (__lzcnt16(0x1) != 15) { + fprintf(stderr, "__lzcnt16(0x1) != 15\n"); + return -1; + } + + if (__lzcnt16(0xFF) != 8) { + fprintf(stderr, "__lzcnt16(0xFF) != 8\n"); + return -1; + } + + if (__lzcnt16(0xFFFF) != 0) { + fprintf(stderr, "__lzcnt16(0xFFFF) != 0\n"); + return -1; + } + + return 1; +} + +int test_lzcnt64() +{ + if (__lzcnt64(0x0) != 64) { + fprintf(stderr, "__lzcnt64(0x0) != 64\n"); + return -1; + } + + if (__lzcnt64(0x1) != 63) { + fprintf(stderr, "__lzcnt64(0x1) != 63\n"); + return -1; + } + + if (__lzcnt64(0xFF) != 56) { + fprintf(stderr, "__lzcnt64(0xFF) != 56\n"); + return -1; + } + + if (__lzcnt64(0xFFFF) != 48) { + fprintf(stderr, "__lzcnt64(0xFFFF) != 48\n"); + return -1; + } + + if (__lzcnt64(0xFFFFFF) != 40) { + fprintf(stderr, "__lzcnt64(0xFFFFFF) != 40\n"); + return -1; + } + + if (__lzcnt64(0xFFFFFFFF) != 32) { + fprintf(stderr, "__lzcnt64(0xFFFFFFFF) != 32\n"); + return -1; + } + + return 1; +} + +int TestIntrinsics(int argc, char* argv[]) +{ + test_lzcnt(); + test_lzcnt16(); + test_lzcnt64(); + + return 0; +} + diff --git a/winpr/libwinpr/utils/collections/BitStream.c b/winpr/libwinpr/utils/collections/BitStream.c index 5604a5e20..ebe47f282 100644 --- a/winpr/libwinpr/utils/collections/BitStream.c +++ b/winpr/libwinpr/utils/collections/BitStream.c @@ -316,13 +316,13 @@ void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits) #endif -void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity) +void BitStream_Attach(wBitStream* bs, const BYTE* buffer, UINT32 capacity) { bs->position = 0; bs->buffer = buffer; bs->offset = 0; bs->accumulator = 0; - bs->pointer = bs->buffer; + bs->pointer = (BYTE*) bs->buffer; bs->capacity = capacity; bs->length = bs->capacity * 8; }