ESCAPE_DEC3 Code Example (Compact 7)
3/12/2014
The ESCAPE_DEC3 escape sequence offloads the RemoteFX display data to the specialized hardware decoder for decoding and optionally, transfers decoded data back to system memory. The decoded data is handled in hardware, such as in video memory, because the data is no longer in system memory. We do not recommend the option of transferring decoded data back to system memory because the memory transfer causes slower performance.
The following code example shows the structure declarations that are required for the ESCAPE_DEC3 escape sequence.
Important
For readability, the following code examples do not contain security or error handling. Do not use the following code examples in a production environment.
#define ESCAPE_DEC3 (ESCAPE_CODE_BEGIN+1)
struct ct_rect
{
LONG left;
LONG top;
LONG right;
LONG bottom;
};
typedef struct ct_rect CtRect;
struct Rect
{
short llX;
short llY;
short urX;
short urY;
};
typedef struct
{
int size;
BYTE buffer;
}
Buffer1D;
struct esc_dec3_in
{
struct _hdr hdr;
UCHAR* comp_data;
ULONG comp_data_size;
struct ct_rect* rects;
ULONG rect_size;
UCHAR* uncomp_data;
ULONG uncomp_data_size;
};
struct esc_dec3_out
{
struct dec3_out ioctl_dec3_out;
ULONG channelId;
ULONG nBytesConsumed;
};
struct _IndexBuffer
{
// const: 0xABCDDCB1
ULONG marker;
ULONG width;
ULONG height;
PVOID tileset;
PVOID* tileBuffer;
PULONG tileBufferLength;
}
typedef struct tagTS_GFX_RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} TS_GFX_RECT, *PTS_GFX_RECT;
// Refer to the RemoteFX protocol specification for more details related to the
// following structures.
typedef struct TagTS_RFX_CODEC_QUANT
{
// Level-3 quantization factor.
BYTE LL3 : 4;
BYTE LH3 : 4;
BYTE HL3 : 4;
BYTE HH3 : 4;
// Level-2 quantization factor.
BYTE LH2 : 4;
BYTE HL2 : 4;
BYTE HH2 : 4;
// Level-1 quantization factor.
BYTE LH1 : 4;
BYTE HL1 : 4;
BYTE HH1 : 4;
}
TS_RFX_CODEC_QUANT;
typedef struct TagTS_RFX_TILE
{
// H/w Tile Marker:0x90ff
USHORT marker;
// 0xa
USHORT size
// The X-index of the encoded tile in the screen tile grid.
BYTE xIdx;
// The Y-index of the encoded tile in the screen tile grid.
BYTE yIdx;
// Specifies the size, in bytes, of the Y-Data field of YUVData.
USHORT YLen;
// Specifies the size, in bytes, of the U-Data field of YUVData.
USHORT ULen;
// Specifies the size, in bytes, of the V-Data field of YUVData.
USHORT VLen;
// The start of the encoded data for the YUV-component of the tile.
BYTE YUVData[1];
} TS_RFX_TILE;
typedef struct TagTS_RFX_TILESET
{
// Block Type WBT_EXTENSION: 0xCCC7
USHORT blockType;
UINT blockLen;
// const: 1
BYTE codecId;
BYTE channelId;
// 0xCAC2
USHORT subtype;
USHORT idx;
USHORT lt : 1;
USHORT flags : 3;
USHORT cct : 2;
USHORT xft : 4;
USHORT et : 4;
USHORT qt : 2;
BYTE numQuant;
BYTE tileSize;
USHORT numTiles;
ULONG tilesDataSize;
TS_RFX_CODEC_QUANT quantVals;
TS_RFX_TILE tiles[1];
} TS_RFX_TILESET;
The following code example shows how the ESCAPE_DEC3 sequence is implemented in a display driver. The esc_dec3 function validates the escape parameters and the escape header received from the RDP client to ensure that the input buffer is from a trusted source.
#define OUTRECTS_BUFFER_SIZE_DFLT 128
// Global variable declaration
Buffer1D _OutBuf;
Rect *_pOutRects;
int _cOutRects;
int _cOutRectsSize;
int Width;
int Height;
int TileSize;
PTS_GFX_RECT pDestFrame;
BOOL esc_dec3(
SURFOBJ* pso,
ULONG iEsc,
ULONG cjIn,
PVOID pvIn,
ULONG cjOut,
PVOID pvOut
)
{
struct esc_dec3_in* p_in = NULL;
struct esc_dec3_out* p_out = NULL;
struct _IndexBuffer* _InBuf = NULL;
struct ct_rect* rects = NULL;
BOOL status = FALSE;
ULONG bytesConsumed = 0;
int nChannelID;
int cbConsumed = 0;
do {
if (!pso)
{
break;
}
if (
(!pvIn)
||
(cjIn != sizeof(*p_in)))
{
break;
}
p_in = (struct esc_dec3_in*)pvIn;
if (
(p_in->hdr.code != iEsc)
||
(p_in->hdr.magic != ESCAPE_MAGIN_IN)
||
(p_in->hdr.size != sizeof(*p_in)))
{
break;
}
if (
(!pvOut)
||
(cjOut != sizeof(*p_out)))
{
break;
}
p_out = (struct esc_dec3_out*)pvOut;
Buffer1D InBuf;
_InBuf = (struct _IndexBuffer*)p_in->comp_data;
p_out->nBytesConsumed = p_in->comp_data_size;
p_out->ioctl_dec3_out.cx = _InBuf->width;
p_out->ioctl_dec3_out.cy = _InBuf->height;
//During initialization, allocate memory as shown below
pDestFrame = (PTS_GFX_RECT)malloc(sizeof PTS_GFX_RECT);
pDestFrame->left =0;
pDestFrame->top =0;
pDestFrame->right =0;
pDestFrame->bottom=0;
TS_RFX_TILESET *tileSet = reinterpret_cast<TS_RFX_TILESET*>(_InBuf->tileset);
// Call ScanSyncFrameBeginBlock function only when registry
// FullScreenRFXonly is set.
// Refer to the Full Screen Mode section for more details.
ScanSyncFrameBeginBlock((BYTE * )_InBuf->tileset);
InBuf.buffer = (BYTE )_InBuf->tileset;
InBuf.size = tileSet->tilesDataSize;
_pOutRects = (Rect *)malloc(OUTRECTS_BUFFER_SIZE_DFLT * sizeof(Rect));
_cOutRectsSize = OUTRECTS_BUFFER_SIZE_DFLT;
Width = _InBuf->width;
Height = _InBuf->height;
TileSize = tileSet->tileSize;
for(ULONG i=0; i< tileSet->numTiles; i++)
{
BYTE *buf = (BYTE*)_InBuf->tileBuffer[i];
TS_RFX_TILE *pTile =reinterpret_cast<TS_RFX_TILE*>(buf);
int xIdx = pTile->xIdx;
int yIdx = pTile->yIdx;
int lftX = xIdx * TileSize;
int lftY = yIdx * TileSize;
int rgtX = lftX + TileSize;
int rgtY = lftY + TileSize;
p_in->rects[i].left = lftX;
p_in->rects[i].top = lftY;
p_in->rects[i].right = rgtX;
p_in->rects[i].bottom = rgtY;
}
// Allocate buffer for the rectangle list returned by the decoder
_OutBuf.size = Width * Height * 32 / 8;
_OutBuf.buffer = BYTE(malloc(_OutBuf.size));
Buffer1D *pOutBuf = (_OutBuf.buffer) ? &_OutBuf : NULL;
//TO DO: The encoded data will be decoded using the specialized hardware decoder
//such as ASIC or DSP. The Decode function below needs to be implemented by the
//decoder driver, which will interface with specialized hardware.
//The decoder driver will drive the decoding process, off-loading the data to
//specialized hardware. It communicates with the hardware through the display
//driver interface and transfers compressed tiles into the decoder.
Decode(InBuf, _cOutRectsSize, _pOutRects, _cOutRects, cbConsumed,
nChannelID, Width, Height, pOutBuf);
p_out->ioctl_dec3_out.rect_count = tileSet->numTiles;
status = TRUE;
} while (0);
return status;
}
The encoded data is decoded by using a specialized hardware decoder, such as ASIC or a DSP. The Decode function in the previous example needs to be implemented by a decoder driver, which interfaces with specialized hardware. The decoder driver drives the decoding process, off-loading the data to specialized hardware. The decoder driver communicates with the hardware through the display driver interface and transfers compressed tiles into the decoder. DMA is recommended to transfer the decoded data in video memory without overloading the processor. If you do not use DMA, the processor copies all the data from the source to the destination, making the processor unavailable for other tasks.