rdpgfx: Implementation for server side channel

server/shadow: support h264 codec with gfx channel
This commit is contained in:
zihao.jiang 2016-04-24 01:49:10 +08:00
parent 5b2455f314
commit 746a754244
27 changed files with 2432 additions and 344 deletions

View File

@ -21,3 +21,6 @@ if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -22,8 +22,8 @@ set(${MODULE_PREFIX}_SRCS
rdpgfx_main.h
rdpgfx_codec.c
rdpgfx_codec.h
rdpgfx_common.c
rdpgfx_common.h)
../rdpgfx_common.c
../rdpgfx_common.h)
include_directories(..)

View File

@ -54,7 +54,8 @@ const char* RDPGFX_CMDID_STRINGS[] =
"RDPGFX_CMDID_CAPSADVERTISE",
"RDPGFX_CMDID_CAPSCONFIRM",
"RDPGFX_CMDID_UNUSED_0014",
"RDPGFX_CMDID_MAPSURFACETOWINDOW"
"RDPGFX_CMDID_MAPSURFACETOWINDOW",
"RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE"
};
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId)

View File

@ -0,0 +1,34 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_server("rdpgfx")
set(${MODULE_PREFIX}_SRCS
rdpgfx_main.c
rdpgfx_main.h
../rdpgfx_common.c
../rdpgfx_common.h)
include_directories(..)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Graphics Pipeline Extension
*
* Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H
#define FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H
#include <freerdp/server/rdpgfx.h>
#include <freerdp/codec/zgfx.h>
struct _rdpgfx_server_private
{
ZGFX_CONTEXT* zgfx;
HANDLE thread;
HANDLE stopEvent;
void* rdpgfx_channel;
DWORD SessionId;
BOOL opened;
};
#endif /* FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H */

View File

@ -73,6 +73,7 @@ typedef BYTE RDPGFX_PIXELFORMAT;
#define RDPGFX_CMDID_CAPSCONFIRM 0x0013
#define RDPGFX_CMDID_UNUSED_0014 0x0014
#define RDPGFX_CMDID_MAPSURFACETOWINDOW 0x0015
#define RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE 0x0016
#define RDPGFX_HEADER_SIZE 8
@ -372,6 +373,14 @@ struct _RDPGFX_AVC444_BITMAP_STREAM
};
typedef struct _RDPGFX_AVC444_BITMAP_STREAM RDPGFX_AVC444_BITMAP_STREAM;
struct _RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU
{
UINT32 frameId;
UINT32 timestamp;
UINT16 timeDiffSE;
UINT16 timeDiffEDR;
};
typedef struct _RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU;
#endif /* FREERDP_CHANNEL_RDPGFX_H */

View File

@ -28,6 +28,10 @@
#define ZGFX_SEGMENTED_SINGLE 0xE0
#define ZGFX_SEGMENTED_MULTIPART 0xE1
#define ZGFX_PACKET_COMPR_TYPE_RDP8 0x04
#define ZGFX_SEGMENTED_MAXSIZE 65535
struct _ZGFX_CONTEXT
{
BOOL Compressor;
@ -53,8 +57,9 @@ typedef struct _ZGFX_CONTEXT ZGFX_CONTEXT;
extern "C" {
#endif
FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags);
FREERDP_API void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush);

View File

@ -0,0 +1,96 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Graphics Pipeline Extension
*
* Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_SERVER_RDPGFX_H
#define FREERDP_CHANNEL_SERVER_RDPGFX_H
#include <freerdp/channels/rdpgfx.h>
typedef struct _rdpgfx_server_context RdpgfxServerContext;
typedef struct _rdpgfx_server_private RdpgfxServerPrivate;
typedef BOOL (*psRdpgfxServerOpen)(RdpgfxServerContext* context);
typedef BOOL (*psRdpgfxServerClose)(RdpgfxServerContext* context);
typedef UINT (*pcRdpgfxResetGraphics)(RdpgfxServerContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics);
typedef UINT (*pcRdpgfxStartFrame)(RdpgfxServerContext* context, RDPGFX_START_FRAME_PDU* startFrame);
typedef UINT (*pcRdpgfxEndFrame)(RdpgfxServerContext* context, RDPGFX_END_FRAME_PDU* endFrame);
typedef UINT (*pcRdpgfxSurfaceCommand)(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd);
typedef UINT (*pcRdpgfxDeleteEncodingContext)(RdpgfxServerContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext);
typedef UINT (*pcRdpgfxCreateSurface)(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface);
typedef UINT (*pcRdpgfxDeleteSurface)(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface);
typedef UINT (*pcRdpgfxSolidFill)(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_PDU* solidFill);
typedef UINT (*pcRdpgfxSurfaceToSurface)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface);
typedef UINT (*pcRdpgfxSurfaceToCache)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache);
typedef UINT (*pcRdpgfxCacheToSurface)(RdpgfxServerContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface);
typedef UINT (*pcRdpgfxCacheImportOffer)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer);
typedef UINT (*pcRdpgfxCacheImportReply)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply);
typedef UINT (*pcRdpgfxEvictCacheEntry)(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry);
typedef UINT (*pcRdpgfxMapSurfaceToOutput)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput);
typedef UINT (*pcRdpgfxMapSurfaceToWindow)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow);
typedef UINT (*pcRdpgfxCapsAdvertise)(RdpgfxServerContext* context, RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise);
typedef UINT (*pcRdpgfxCapsConfirm)(RdpgfxServerContext* context, RDPGFX_CAPS_CONFIRM_PDU* capsConfirm);
typedef UINT (*pcRdpgfxFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge);
typedef UINT (*pcRdpgfxQoeFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge);
struct _rdpgfx_server_context
{
HANDLE vcm;
void* custom;
psRdpgfxServerOpen Open;
psRdpgfxServerClose Close;
pcRdpgfxResetGraphics ResetGraphics;
pcRdpgfxStartFrame StartFrame;
pcRdpgfxEndFrame EndFrame;
pcRdpgfxSurfaceCommand SurfaceCommand;
pcRdpgfxDeleteEncodingContext DeleteEncodingContext;
pcRdpgfxCreateSurface CreateSurface;
pcRdpgfxDeleteSurface DeleteSurface;
pcRdpgfxSolidFill SolidFill;
pcRdpgfxSurfaceToSurface SurfaceToSurface;
pcRdpgfxSurfaceToCache SurfaceToCache;
pcRdpgfxCacheToSurface CacheToSurface;
pcRdpgfxCacheImportOffer CacheImportOffer;
pcRdpgfxCacheImportReply CacheImportReply;
pcRdpgfxEvictCacheEntry EvictCacheEntry;
pcRdpgfxMapSurfaceToOutput MapSurfaceToOutput;
pcRdpgfxMapSurfaceToWindow MapSurfaceToWindow;
pcRdpgfxCapsAdvertise CapsAdvertise;
pcRdpgfxCapsConfirm CapsConfirm;
pcRdpgfxFrameAcknowledge FrameAcknowledge;
pcRdpgfxQoeFrameAcknowledge QoeFrameAcknowledge;
RdpgfxServerPrivate* priv;
rdpContext* rdpcontext;
};
#ifdef __cplusplus
extern "C" {
#endif
FREERDP_API RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm);
FREERDP_API void rdpgfx_server_context_free(RdpgfxServerContext* context);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_CHANNEL_SERVER_RDPGFX_H */

View File

@ -33,6 +33,7 @@
#include <freerdp/server/remdesk.h>
#include <freerdp/server/rdpsnd.h>
#include <freerdp/server/audin.h>
#include <freerdp/server/rdpgfx.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/region.h>
@ -87,6 +88,7 @@ struct rdp_shadow_client
BOOL inLobby;
BOOL mayView;
BOOL mayInteract;
BOOL suppressOutput;
wMessageQueue* MsgQueue;
CRITICAL_SECTION lock;
REGION16 invalidRegion;
@ -102,6 +104,7 @@ struct rdp_shadow_client
RemdeskServerContext* remdesk;
RdpsndServerContext* rdpsnd;
audin_server_context* audin;
RdpgfxServerContext* rdpgfx;
};
struct rdp_shadow_server
@ -169,9 +172,12 @@ struct _RDP_SHADOW_ENTRY_POINTS
int selectedMonitor; \
MONITOR_DEF monitors[16]; \
MONITOR_DEF virtualScreen; \
\
/* This event indicates that we have graphic change */ \
/* such as screen update and resize. It should not be */ \
/* used by subsystem implementation directly */ \
rdpShadowMultiClientEvent* updateEvent; \
BOOL suppressOutput; \
REGION16 invalidRegion; \
\
wMessagePipe* MsgPipe; \
UINT32 pointerX; \
UINT32 pointerY; \
@ -201,22 +207,7 @@ struct rdp_shadow_subsystem
};
/* Definition of message between subsystem and clients */
#define SHADOW_MSG_IN_REFRESH_OUTPUT_ID 1001
#define SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID 1002
struct _SHADOW_MSG_IN_REFRESH_OUTPUT
{
UINT32 numRects;
RECTANGLE_16* rects;
};
typedef struct _SHADOW_MSG_IN_REFRESH_OUTPUT SHADOW_MSG_IN_REFRESH_OUTPUT;
struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT
{
BOOL allow;
RECTANGLE_16 rect;
};
typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT;
#define SHADOW_MSG_IN_REFRESH_REQUEST_ID 1001
typedef struct _SHADOW_MSG_OUT SHADOW_MSG_OUT;
typedef void (*MSG_OUT_FREE_FN)(UINT32 id, SHADOW_MSG_OUT* msg); /* function to free SHADOW_MSG_OUT */

View File

@ -1,10 +1,217 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/bitstream.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/zgfx.h>
#include <freerdp/log.h>
int TestFreeRDPCodecZGfx(int argc, char* argv[])
/* Sample from [MS-RDPEGFX] */
static const BYTE TEST_FOX_DATA[] =
"The quick brown "
"fox jumps over t"
"he lazy dog";
static const BYTE TEST_FOX_DATA_SINGLE[] =
"\xE0\x04\x54\x68\x65\x20\x71\x75\x69\x63\x6B\x20\x62\x72\x6F\x77"
"\x6E\x20\x66\x6F\x78\x20\x6A\x75\x6D\x70\x73\x20\x6F\x76\x65\x72"
"\x20\x74\x68\x65\x20\x6C\x61\x7A\x79\x20\x64\x6F\x67";
static const BYTE TEST_FOX_DATA_MULTIPART[] =
"\xE1\x03\x00\x2B\x00\x00\x00\x11\x00\x00\x00\x04\x54\x68\x65\x20"
"\x71\x75\x69\x63\x6B\x20\x62\x72\x6F\x77\x6E\x20\x0E\x00\x00\x00"
"\x04\x66\x6F\x78\x20\x6A\x75\x6D\x70\x73\x20\x6F\x76\x65\x10\x00"
"\x00\x00\x24\x39\x08\x0E\x91\xF8\xD8\x61\x3D\x1E\x44\x06\x43\x79"
"\x9C\x02";
int test_ZGfxCompressFox()
{
int status;
UINT32 Flags;
BYTE* pSrcData;
UINT32 SrcSize;
UINT32 DstSize;
BYTE* pDstData;
ZGFX_CONTEXT* zgfx;
UINT32 expectedSize;
zgfx = zgfx_context_new(TRUE);
SrcSize = sizeof(TEST_FOX_DATA) - 1;
pSrcData = (BYTE*) TEST_FOX_DATA;
Flags = 0;
expectedSize = sizeof(TEST_FOX_DATA_SINGLE) - 1;
status = zgfx_compress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("flags: 0x%04X size: %d\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxCompressFox: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
return -1;
}
if (memcmp(pDstData, TEST_FOX_DATA_SINGLE, DstSize) != 0)
{
printf("test_ZGfxCompressFox: output mismatch\n");
printf("Actual\n");
BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__FUNCTION__, WLOG_INFO, TEST_FOX_DATA_SINGLE, DstSize * 8, 0);
return -1;
}
zgfx_context_free(zgfx);
return 0;
}
int test_ZGfxDecompressFoxSingle()
{
int status;
UINT32 Flags;
BYTE* pSrcData;
UINT32 SrcSize;
UINT32 DstSize;
BYTE* pDstData;
ZGFX_CONTEXT* zgfx;
UINT32 expectedSize;
zgfx = zgfx_context_new(TRUE);
SrcSize = sizeof(TEST_FOX_DATA_SINGLE) - 1;
pSrcData = (BYTE*) TEST_FOX_DATA_SINGLE;
Flags = 0;
expectedSize = sizeof(TEST_FOX_DATA) - 1;
status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
printf("flags: 0x%04X size: %d\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
return -1;
}
if (memcmp(pDstData, TEST_FOX_DATA, DstSize) != 0)
{
printf("test_ZGfxDecompressFoxSingle: output mismatch\n");
printf("Actual\n");
BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__FUNCTION__, WLOG_INFO, TEST_FOX_DATA, DstSize * 8, 0);
return -1;
}
zgfx_context_free(zgfx);
return 0;
}
int test_ZGfxDecompressFoxMultipart()
{
int status;
UINT32 Flags;
BYTE* pSrcData;
UINT32 SrcSize;
UINT32 DstSize;
BYTE* pDstData;
ZGFX_CONTEXT* zgfx;
UINT32 expectedSize;
zgfx = zgfx_context_new(TRUE);
SrcSize = sizeof(TEST_FOX_DATA_MULTIPART) - 1;
pSrcData = (BYTE*) TEST_FOX_DATA_MULTIPART;
Flags = 0;
expectedSize = sizeof(TEST_FOX_DATA) - 1;
status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
printf("flags: 0x%04X size: %d\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
return -1;
}
if (memcmp(pDstData, TEST_FOX_DATA, DstSize) != 0)
{
printf("test_ZGfxDecompressFoxSingle: output mismatch\n");
printf("Actual\n");
BitDump(__FUNCTION__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__FUNCTION__, WLOG_INFO, TEST_FOX_DATA, DstSize * 8, 0);
return -1;
}
zgfx_context_free(zgfx);
return 0;
}
int test_ZGfxCompressConsistent()
{
int status;
UINT32 Flags;
BYTE* pSrcData;
UINT32 SrcSize;
UINT32 DstSize;
BYTE* pDstData;
UINT32 DstSize2;
BYTE* pDstData2;
ZGFX_CONTEXT* zgfx;
UINT32 expectedSize;
BYTE BigBuffer[65536];
memset(BigBuffer, 0xaa, sizeof(BigBuffer));
memcpy(BigBuffer, TEST_FOX_DATA, sizeof(TEST_FOX_DATA) - 1);
zgfx = zgfx_context_new(TRUE);
/* Compress */
expectedSize = SrcSize = sizeof(BigBuffer);
pSrcData = (BYTE*) BigBuffer;
Flags = 0;
status = zgfx_compress(zgfx, pSrcData, SrcSize, &pDstData2, &DstSize2, &Flags);
printf("Compress: flags: 0x%04X size: %d\n", Flags, DstSize2);
/* Decompress */
status = zgfx_decompress(zgfx, pDstData2, DstSize2, &pDstData, &DstSize, Flags);
printf("Decompress: flags: 0x%04X size: %d\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
return -1;
}
if (memcmp(pDstData, BigBuffer, DstSize) != 0)
{
printf("test_ZGfxDecompressFoxSingle: output mismatch\n");
printf("Actual\n");
BitDump(__FUNCTION__, WLOG_INFO, pDstData, 64 * 8, 0);
printf("...\n");
BitDump(__FUNCTION__, WLOG_INFO, pDstData + DstSize - 64, 64 * 8, 0);
printf("Expected\n");
BitDump(__FUNCTION__, WLOG_INFO, BigBuffer, 64 * 8, 0);
printf("...\n");
BitDump(__FUNCTION__, WLOG_INFO, BigBuffer + DstSize - 64, 64 * 8, 0);
printf("Middle Result\n");
BitDump(__FUNCTION__, WLOG_INFO, pDstData2, 64 * 8, 0);
printf("...\n");
BitDump(__FUNCTION__, WLOG_INFO, pDstData2 + DstSize2 - 64, 64 * 8, 0);
return -1;
}
zgfx_context_free(zgfx);
return 0;
}
int TestFreeRDPCodecZGfx(int argc, char* argv[])
{
if (test_ZGfxCompressFox() < 0)
return -1;
if (test_ZGfxDecompressFoxSingle() < 0)
return -1;
if (test_ZGfxDecompressFoxMultipart() < 0)
return -1;
if (test_ZGfxCompressConsistent() < 0)
return -1;
return 0;
}

View File

@ -25,8 +25,11 @@
#include <winpr/print.h>
#include <winpr/bitstream.h>
#include <freerdp/log.h>
#include <freerdp/codec/zgfx.h>
#define TAG FREERDP_TAG("codec")
/**
* RDP8 Compressor Limits:
*
@ -188,7 +191,7 @@ void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* zgfx, int offset, BYTE* dst, UI
while ((bytesLeft -= bytes) > 0);
}
int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, UINT32 cbSegment)
static int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, UINT32 cbSegment)
{
BYTE c;
BYTE flags;
@ -383,11 +386,106 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
return 1;
}
int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
static int zgfx_compress_segment(ZGFX_CONTEXT* zgfx, wStream* s, BYTE* pSrcData, UINT32 SrcSize, UINT32* pFlags)
{
/* FIXME: Currently compression not implemented. Just copy the raw source */
if (!Stream_EnsureRemainingCapacity(s, SrcSize + 1))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return -1;
}
(*pFlags) |= ZGFX_PACKET_COMPR_TYPE_RDP8; /* RDP 8.0 compression format */
Stream_Write_UINT8(s, (*pFlags)); /* header (1 byte) */
Stream_Write(s, pSrcData, SrcSize);
return 1;
}
int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags)
{
int fragment;
UINT16 maxLength;
UINT32 totalLength;
UINT16* pSegmentCount = NULL;
BYTE* pSrcData;
int status = 0;
maxLength = ZGFX_SEGMENTED_MAXSIZE;
totalLength = uncompressedSize;
pSrcData = pUncompressed;
for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
{
UINT32 SrcSize;
UINT32* pDstSize;
UINT32 position;
SrcSize = (totalLength > maxLength) ? maxLength : totalLength;
pDstSize = NULL;
totalLength -= SrcSize;
if (fragment == 0)
{
/* First fragment */
/* descriptor (1 byte) */
Stream_Write_UINT8(sDst, (totalLength == 0) ?
ZGFX_SEGMENTED_SINGLE : ZGFX_SEGMENTED_MULTIPART);
if (totalLength > 0)
{
pSegmentCount = (UINT16*)Stream_Pointer(sDst); /* segmentCount (2 bytes) */
Stream_Seek(sDst, 2);
Stream_Write_UINT32(sDst, uncompressedSize); /* uncompressedSize (4 bytes) */
}
}
else if (totalLength == 0)
{
/* Last fragment */
if (pSegmentCount)
{
(*pSegmentCount) = fragment + 1;
}
}
if (fragment > 0 || totalLength > 0)
{
/* Multipart */
pDstSize = (UINT32*)Stream_Pointer(sDst); /* size (4 bytes) */
Stream_Seek(sDst, 4);
}
position = Stream_GetPosition(sDst);
if ((status = zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags)) < 0)
{
return status;
}
if (pDstSize)
{
(*pDstSize) = Stream_GetPosition(sDst) - position;
}
pSrcData += SrcSize;
}
return status;
}
int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
{
int status;
wStream* s = Stream_New(NULL, SrcSize);
status = zgfx_compress_to_stream(zgfx, s, pSrcData, SrcSize, pFlags);
(*ppDstData) = Stream_Buffer(s);
(*pDstSize) = Stream_GetPosition(s);
Stream_Free(s, FALSE);
return status;
}
void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush)
{
zgfx->HistoryIndex = 0;

View File

@ -45,6 +45,8 @@ set(${MODULE_PREFIX}_SRCS
shadow_rdpsnd.h
shadow_audin.c
shadow_audin.h
shadow_rdpgfx.c
shadow_rdpgfx.h
shadow_subsystem.c
shadow_subsystem.h
shadow_mcevent.c

View File

@ -268,6 +268,7 @@ int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
size_t numRects;
const CGRect* rects;
RECTANGLE_16 invalidRect;
rdpShadowSurface* surface = subsystem->server->surface;
rects = CGDisplayStreamUpdateGetRects(subsystem->lastUpdate, kCGDisplayStreamUpdateDirtyRects, &numRects);
@ -290,7 +291,7 @@ int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
invalidRect.bottom /= 2;
}
region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect);
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
}
return 0;
@ -326,11 +327,11 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa
surfaceRect.right = surface->width;
surfaceRect.bottom = surface->height;
region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect);
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
if (!region16_is_empty(&(subsystem->invalidRegion)))
if (!region16_is_empty(&(surface->invalidRegion)))
{
extents = region16_extents(&(subsystem->invalidRegion));
extents = region16_extents(&(surface->invalidRegion));
x = extents->left;
y = extents->top;
@ -375,7 +376,7 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa
ArrayList_Unlock(server->clients);
region16_clear(&(subsystem->invalidRegion));
region16_clear(&(surface->invalidRegion));
}
if (status != kCGDisplayStreamFrameStatusFrameComplete)
@ -446,46 +447,9 @@ int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage
{
switch(message->id)
{
case SHADOW_MSG_IN_REFRESH_OUTPUT_ID:
{
UINT32 index;
SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
if (msg->numRects)
{
for (index = 0; index < msg->numRects; index++)
{
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &msg->rects[index]);
}
}
else
{
RECTANGLE_16 refreshRect;
refreshRect.left = 0;
refreshRect.top = 0;
refreshRect.right = subsystem->width;
refreshRect.bottom = subsystem->height;
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &refreshRect);
}
case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem);
break;
}
case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID:
{
SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
if (msg->allow)
{
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &(msg->rect));
}
break;
}
default:
WLog_ERR(TAG, "Unknown message id: %u", message->id);
break;

View File

@ -638,6 +638,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
RECT* pDirtyRectsBuffer;
DXGI_OUTDUPL_MOVE_RECT* pMoveRect;
DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer;
rdpShadowSurface* surface = subsystem->server->surface;
if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0)
return 0;
@ -704,7 +705,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
invalidRect.right = (UINT16) pDstRect->right;
invalidRect.bottom = (UINT16) pDstRect->bottom;
region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect);
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
}
numDirtyRects = DirtyRectsBufferSize / sizeof(RECT);
@ -718,7 +719,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
invalidRect.right = (UINT16) pDirtyRect->right;
invalidRect.bottom = (UINT16) pDirtyRect->bottom;
region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect);
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
}
return 1;

View File

@ -63,6 +63,7 @@ BOOL shw_end_paint(rdpContext* context)
rdpGdi* gdi = context->gdi;
shwContext* shw = (shwContext*) context;
winShadowSubsystem* subsystem = shw->subsystem;
rdpShadowSurface* surface = subsystem->server->surface;
ninvalid = gdi->primary->hdc->hwnd->ninvalid;
cinvalid = gdi->primary->hdc->hwnd->cinvalid;
@ -74,7 +75,7 @@ BOOL shw_end_paint(rdpContext* context)
invalidRect.right = cinvalid[index].x + cinvalid[index].w;
invalidRect.bottom = cinvalid[index].y + cinvalid[index].h;
region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect);
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
}
SetEvent(subsystem->RdpUpdateEnterEvent);

View File

@ -219,7 +219,7 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
if (ArrayList_Count(server->clients) < 1)
{
region16_clear(&(subsystem->invalidRegion));
region16_clear(&(surface->invalidRegion));
return 1;
}
@ -228,12 +228,12 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
surfaceRect.right = surface->x + surface->width;
surfaceRect.bottom = surface->y + surface->height;
region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect);
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
if (region16_is_empty(&(subsystem->invalidRegion)))
if (region16_is_empty(&(surface->invalidRegion)))
return 1;
extents = region16_extents(&(subsystem->invalidRegion));
extents = region16_extents(&(surface->invalidRegion));
CopyMemory(&invalidRect, extents, sizeof(RECTANGLE_16));
shadow_capture_align_clip_rect(&invalidRect, &surfaceRect);
@ -286,7 +286,7 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
ArrayList_Unlock(server->clients);
region16_clear(&(subsystem->invalidRegion));
region16_clear(&(surface->invalidRegion));
return 1;
}

View File

@ -763,9 +763,6 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
if (count < 1)
return 1;
if ((count == 1) && subsystem->suppressOutput)
return 1;
surfaceRect.left = 0;
surfaceRect.top = 0;
surfaceRect.right = surface->width;
@ -814,12 +811,12 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
XUnlockDisplay(subsystem->display);
region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect);
region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect);
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
if (!region16_is_empty(&(subsystem->invalidRegion)))
if (!region16_is_empty(&(surface->invalidRegion)))
{
extents = region16_extents(&(subsystem->invalidRegion));
extents = region16_extents(&(surface->invalidRegion));
x = extents->left;
y = extents->top;
@ -849,7 +846,7 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
}
}
region16_clear(&(subsystem->invalidRegion));
region16_clear(&(surface->invalidRegion));
}
if (!subsystem->use_xshm)
@ -868,46 +865,9 @@ int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage
{
switch(message->id)
{
case SHADOW_MSG_IN_REFRESH_OUTPUT_ID:
{
UINT32 index;
SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
if (msg->numRects)
{
for (index = 0; index < msg->numRects; index++)
{
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &msg->rects[index]);
}
}
else
{
RECTANGLE_16 refreshRect;
refreshRect.left = 0;
refreshRect.top = 0;
refreshRect.right = subsystem->width;
refreshRect.bottom = subsystem->height;
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &refreshRect);
}
case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem);
break;
}
case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID:
{
SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
if (msg->allow)
{
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &(msg->rect));
}
break;
}
default:
WLog_ERR(TAG, "Unknown message id: %u", message->id);
break;

View File

@ -43,11 +43,21 @@ UINT shadow_client_channels_post_connect(rdpShadowClient* client)
shadow_client_audin_init(client);
if (client->context.settings->SupportGraphicsPipeline)
{
shadow_client_rdpgfx_init(client);
}
return CHANNEL_RC_OK;
}
void shadow_client_channels_free(rdpShadowClient* client)
{
if (client->context.settings->SupportGraphicsPipeline)
{
shadow_client_rdpgfx_uninit(client);
}
shadow_client_audin_uninit(client);
shadow_client_rdpsnd_uninit(client);

View File

@ -28,6 +28,7 @@
#include "shadow_remdesk.h"
#include "shadow_rdpsnd.h"
#include "shadow_audin.h"
#include "shadow_rdpgfx.h"
#ifdef __cplusplus
extern "C" {

View File

@ -30,10 +30,62 @@
#include <freerdp/log.h>
#include "libfreerdp/core/server.h"
#include "shadow.h"
#define TAG CLIENT_TAG("shadow")
struct _SHADOW_GFX_STATUS
{
BOOL gfxOpened;
BOOL gfxSurfaceCreated;
};
typedef struct _SHADOW_GFX_STATUS SHADOW_GFX_STATUS;
static void shadow_client_rdpgfx_new_surface(rdpShadowClient *client)
{
RDPGFX_CREATE_SURFACE_PDU createSurface;
RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput;
RdpgfxServerContext* context = client->rdpgfx;
rdpSettings* settings = ((rdpContext*) client)->settings;
createSurface.width = settings->DesktopWidth;
createSurface.height = settings->DesktopHeight;
createSurface.pixelFormat = PIXEL_FORMAT_XRGB_8888;
createSurface.surfaceId = 0;
surfaceToOutput.outputOriginX = 0;
surfaceToOutput.outputOriginY = 0;
surfaceToOutput.surfaceId = 0;
surfaceToOutput.reserved = 0;
IFCALL(context->CreateSurface, context, &createSurface);
IFCALL(context->MapSurfaceToOutput, context, &surfaceToOutput);
}
static void shadow_client_rdpgfx_release_surface(rdpShadowClient *client)
{
RDPGFX_DELETE_SURFACE_PDU pdu;
RdpgfxServerContext* context = client->rdpgfx;
pdu.surfaceId = 0;
IFCALL(context->DeleteSurface, context, &pdu);
}
static void shadow_client_rdpgfx_reset_graphic(rdpShadowClient *client)
{
RDPGFX_RESET_GRAPHICS_PDU pdu;
RdpgfxServerContext* context = client->rdpgfx;
rdpSettings* settings = ((rdpContext*) client)->settings;
pdu.width = settings->DesktopWidth;
pdu.height = settings->DesktopHeight;
pdu.monitorCount = client->subsystem->numMonitors;
pdu.monitorDefArray = client->subsystem->monitors;
IFCALL(context->ResetGraphics, context, &pdu);
}
static void shadow_client_free_queued_message(void *obj)
{
wMessage *message = (wMessage*)obj;
@ -44,7 +96,7 @@ static void shadow_client_free_queued_message(void *obj)
}
}
BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
static BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
{
rdpSettings* settings;
rdpShadowServer* server;
@ -62,7 +114,8 @@ BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
settings->BitmapCacheV3Enabled = TRUE;
settings->FrameMarkerCommandEnabled = TRUE;
settings->SurfaceFrameMarkerEnabled = TRUE;
settings->SupportGraphicsPipeline = FALSE;
settings->SupportGraphicsPipeline = TRUE;
settings->GfxH264 = FALSE;
settings->DrawAllowSkipAlpha = TRUE;
settings->DrawAllowColorSubsampling = TRUE;
@ -130,40 +183,36 @@ fail_cert_file:
return FALSE;
}
void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
static void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
{
rdpShadowServer* server = client->server;
ArrayList_Remove(server->clients, (void*) client);
DeleteCriticalSection(&(client->lock));
region16_uninit(&(client->invalidRegion));
WTSCloseServer((HANDLE) client->vcm);
/* Clear queued messages and free resource */
MessageQueue_Clear(client->MsgQueue);
MessageQueue_Free(client->MsgQueue);
if (client->encoder)
{
shadow_encoder_free(client->encoder);
client->encoder = NULL;
}
/* Clear queued messages and free resource */
MessageQueue_Clear(client->MsgQueue);
MessageQueue_Free(client->MsgQueue);
WTSCloseServer((HANDLE) client->vcm);
client->vcm = NULL;
region16_uninit(&(client->invalidRegion));
DeleteCriticalSection(&(client->lock));
}
void shadow_client_message_free(wMessage* message)
{
switch(message->id)
{
case SHADOW_MSG_IN_REFRESH_OUTPUT_ID:
free(((SHADOW_MSG_IN_REFRESH_OUTPUT*)message->wParam)->rects);
free(message->wParam);
break;
case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID:
free(message->wParam);
case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
/* Refresh request do not have message to free */
break;
default:
@ -173,7 +222,69 @@ void shadow_client_message_free(wMessage* message)
}
}
BOOL shadow_client_capabilities(freerdp_peer* peer)
static void shadow_client_mark_invalid(rdpShadowClient* client, int numRects, const RECTANGLE_16* rects)
{
int index;
RECTANGLE_16 screenRegion;
rdpSettings* settings = ((rdpContext*) client)->settings;
EnterCriticalSection(&(client->lock));
/* Mark client invalid region. No rectangle means full screen */
if (numRects > 0)
{
for (index = 0; index < numRects; index++)
{
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
}
}
else
{
screenRegion.left = 0;
screenRegion.top = 0;
screenRegion.right = settings->DesktopWidth;
screenRegion.bottom = settings->DesktopHeight;
region16_union_rect(&(client->invalidRegion),
&(client->invalidRegion), &screenRegion);
}
LeaveCriticalSection(&(client->lock));
}
/**
* Function description
* Recalculate client desktop size
*
* @return TRUE if width/height changed.
*/
static BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
{
int width, height;
rdpShadowServer* server = client->server;
rdpSettings* settings = client->context.settings;
RECTANGLE_16 viewport = {0, 0, server->surface->width, server->surface->height};
if (server->shareSubRect)
{
rectangles_intersection(&viewport, &(server->subRect), &viewport);
}
width = viewport.right - viewport.left;
height = viewport.bottom - viewport.top;
if (settings->DesktopWidth != (UINT32)width || settings->DesktopHeight != (UINT32)height)
{
settings->DesktopWidth = width;
settings->DesktopHeight = height;
return TRUE;
}
return FALSE;
}
static BOOL shadow_client_capabilities(freerdp_peer* peer)
{
rdpShadowSubsystem* subsystem;
rdpShadowClient* client;
@ -181,34 +292,20 @@ BOOL shadow_client_capabilities(freerdp_peer* peer)
client = (rdpShadowClient*) peer->context;
subsystem = client->server->subsystem;
if (subsystem->ClientCapabilities)
{
return subsystem->ClientCapabilities(subsystem, client);
}
IFCALL(subsystem->ClientCapabilities, subsystem, client);
/* Make sure we send correct width/height to client */
(void)shadow_client_recalc_desktop_size(client);
return TRUE;
}
static INLINE void shadow_client_calc_desktop_size(rdpShadowServer* server, int* pWidth, int* pHeight)
{
RECTANGLE_16 viewport = {0, 0, server->screen->width, server->screen->height};
if (server->shareSubRect)
{
rectangles_intersection(&viewport, &(server->subRect), &viewport);
}
(*pWidth) = viewport.right - viewport.left;
(*pHeight) = viewport.bottom - viewport.top;
}
BOOL shadow_client_post_connect(freerdp_peer* peer)
static BOOL shadow_client_post_connect(freerdp_peer* peer)
{
int authStatus;
int width, height;
rdpSettings* settings;
rdpShadowClient* client;
rdpShadowServer* server;
RECTANGLE_16 invalidRect;
rdpShadowSubsystem* subsystem;
client = (rdpShadowClient*) peer->context;
@ -216,30 +313,29 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
server = client->server;
subsystem = server->subsystem;
shadow_client_calc_desktop_size(server, &width, &height);
settings->DesktopWidth = width;
settings->DesktopHeight = height;
if (settings->ColorDepth == 24)
settings->ColorDepth = 16; /* disable 24bpp */
if (settings->MultifragMaxRequestSize < 0x3F0000)
settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */
WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
WLog_INFO(TAG, "Client from %s is activated (%dx%d@%d)",
peer->hostname, settings->DesktopWidth,
settings->DesktopHeight, settings->ColorDepth);
peer->update->DesktopResize(peer->update->context);
/* Resize client if necessary */
if (shadow_client_recalc_desktop_size(client))
{
peer->update->DesktopResize(peer->update->context);
WLog_INFO(TAG, "Client from %s is resized (%dx%d@%d)",
peer->hostname, settings->DesktopWidth,
settings->DesktopHeight, settings->ColorDepth);
}
if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
return FALSE;
invalidRect.left = 0;
invalidRect.top = 0;
invalidRect.right = server->screen->width;
invalidRect.bottom = server->screen->height;
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect);
shadow_client_mark_invalid(client, 0, NULL);
authStatus = -1;
@ -271,7 +367,7 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
/* Convert rects in sub rect coordinate to client/surface coordinate */
static INLINE void shadow_client_convert_rects(rdpShadowClient* client,
RECTANGLE_16* dst, RECTANGLE_16* src, UINT32 numRects)
RECTANGLE_16* dst, const RECTANGLE_16* src, UINT32 numRects)
{
if (client->server->shareSubRect)
{
@ -289,71 +385,79 @@ static INLINE void shadow_client_convert_rects(rdpShadowClient* client,
}
else
{
CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
if (src != dst)
{
CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
}
}
}
BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
static BOOL shadow_client_refresh_request(rdpShadowClient* client)
{
wMessage message = { 0 };
SHADOW_MSG_IN_REFRESH_OUTPUT* wParam;
wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
message.wParam = NULL;
message.lParam = NULL;
message.context = (void*) client;
message.Free = NULL;
return MessageQueue_Dispatch(MsgPipe->In, &message);
}
static BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
{
RECTANGLE_16* rects;
/* It is invalid if we have area count but no actual area */
if (count && !areas)
return FALSE;
if (!(wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT))))
return FALSE;
wParam->numRects = (UINT32) count;
if (wParam->numRects)
if (count)
{
wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16));
rects = (RECTANGLE_16*) calloc(count, sizeof(RECTANGLE_16));
if (!wParam->rects)
if (!rects)
{
free (wParam);
return FALSE;
}
shadow_client_convert_rects(client, wParam->rects, areas, wParam->numRects);
shadow_client_convert_rects(client, rects, areas, count);
shadow_client_mark_invalid(client, count, rects);
free(rects);
}
else
{
shadow_client_mark_invalid(client, 0, NULL);
}
message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID;
message.wParam = (void*) wParam;
message.lParam = NULL;
message.context = (void*) client;
message.Free = shadow_client_message_free;
return MessageQueue_Dispatch(MsgPipe->In, &message);
return shadow_client_refresh_request(client);
}
BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area)
static BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area)
{
wMessage message = { 0 };
SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam;
wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
RECTANGLE_16 region;
wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT));
if (!wParam)
return FALSE;
wParam->allow = (UINT32) allow;
if (area)
shadow_client_convert_rects(client, &(wParam->rect), area, 1);
message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID;
message.wParam = (void*) wParam;
message.lParam = NULL;
message.context = (void*) client;
message.Free = shadow_client_message_free;
return MessageQueue_Dispatch(MsgPipe->In, &message);
client->suppressOutput = allow ? FALSE : TRUE;
if (allow)
{
if (area)
{
shadow_client_convert_rects(client, &region, area, 1);
shadow_client_mark_invalid(client, 1, &region);
}
else
{
shadow_client_mark_invalid(client, 0, NULL);
}
}
return shadow_client_refresh_request(client);
}
BOOL shadow_client_activate(freerdp_peer* peer)
static BOOL shadow_client_activate(freerdp_peer* peer)
{
rdpSettings* settings = peer->settings;
rdpShadowClient* client = (rdpShadowClient*) peer->context;
@ -375,6 +479,7 @@ BOOL shadow_client_activate(freerdp_peer* peer)
shadow_encoder_reset(client->encoder);
/* Update full screen in next update */
return shadow_client_refresh_rect(client, 0, NULL);
}
@ -439,7 +544,7 @@ BOOL shadow_client_logon(freerdp_peer* peer, SEC_WINNT_AUTH_IDENTITY* identity,
return TRUE;
}
BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
static BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
{
/*
* Record the last client acknowledged frame id to
@ -454,28 +559,91 @@ BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 fra
return TRUE;
}
int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id)
static UINT shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge)
{
SURFACE_FRAME_MARKER surfaceFrameMarker;
rdpContext* context = (rdpContext*) client;
rdpUpdate* update = context->update;
shadow_client_surface_frame_acknowledge((rdpShadowClient *)context->custom,
frameAcknowledge->frameId);
return CHANNEL_RC_OK;
}
surfaceFrameMarker.frameAction = action;
surfaceFrameMarker.frameId = id;
static int shadow_client_send_surface_gfx(rdpShadowClient* client,
BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight)
{
rdpUpdate* update;
rdpContext* context;
rdpSettings* settings;
rdpShadowServer* server;
rdpShadowEncoder* encoder;
RDPGFX_SURFACE_COMMAND cmd;
RDPGFX_START_FRAME_PDU cmdstart;
RDPGFX_END_FRAME_PDU cmdend;
SYSTEMTIME sTime;
IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker);
context = (rdpContext*) client;
update = context->update;
settings = context->settings;
server = client->server;
encoder = client->encoder;
cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
GetSystemTime(&sTime);
cmdstart.timestamp = sTime.wHour << 22 | sTime.wMinute << 16 |
sTime.wSecond << 10 | sTime.wMilliseconds;
cmdend.frameId = cmdstart.frameId;
cmd.surfaceId = 0;
cmd.contextId = 0;
cmd.format = PIXEL_FORMAT_XRGB_8888;
cmd.left = nXSrc;
cmd.top = nYSrc;
cmd.right = cmd.left + nWidth;
cmd.bottom = cmd.top + nHeight;
cmd.width = nWidth;
cmd.height = nHeight;
if (settings->GfxH264)
{
RDPGFX_AVC420_BITMAP_STREAM avc420;
RECTANGLE_16 regionRect;
RDPGFX_H264_QUANT_QUALITY quantQualityVal;
shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420);
avc420_compress(encoder->h264, pSrcData, PIXEL_FORMAT_RGB32, nSrcStep,
nWidth, nHeight, &avc420.data, &avc420.length);
cmd.codecId = RDPGFX_CODECID_AVC420;
cmd.extra = (void *)&avc420;
regionRect.left = cmd.left;
regionRect.top = cmd.top;
regionRect.right = cmd.right;
regionRect.bottom = cmd.bottom;
quantQualityVal.qp = encoder->h264->QP;
quantQualityVal.r = 0;
quantQualityVal.p = 0;
quantQualityVal.qualityVal = 100 - quantQualityVal.qp;
avc420.meta.numRegionRects = 1;
avc420.meta.regionRects = &regionRect;
avc420.meta.quantQualityVals = &quantQualityVal;
IFCALL(client->rdpgfx->StartFrame, client->rdpgfx, &cmdstart);
IFCALL(client->rdpgfx->SurfaceCommand, client->rdpgfx, &cmd);
IFCALL(client->rdpgfx->EndFrame, client->rdpgfx, &cmdend);
}
return 1;
}
int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
static int shadow_client_send_surface_bits(rdpShadowClient* client,
BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight)
{
int i;
BOOL first;
BOOL last;
wStream* s;
int nSrcStep;
BYTE* pSrcData;
int numMessages;
UINT32 frameId = 0;
rdpUpdate* update;
@ -492,24 +660,6 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s
server = client->server;
encoder = client->encoder;
pSrcData = surface->data;
nSrcStep = surface->scanline;
if (server->shareSubRect)
{
int subX, subY;
int subWidth, subHeight;
subX = server->subRect.left;
subY = server->subRect.top;
subWidth = server->subRect.right - server->subRect.left;
subHeight = server->subRect.bottom - server->subRect.top;
nXSrc -= subX;
nYSrc -= subY;
pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
}
if (encoder->frameAck)
frameId = shadow_encoder_create_frame_id(encoder);
@ -613,14 +763,13 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s
return 1;
}
int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
static int shadow_client_send_bitmap_update(rdpShadowClient* client,
BYTE* pSrcData, int nSrcStep, int nXSrc, int nYSrc, int nWidth, int nHeight)
{
BYTE* data;
BYTE* buffer;
int yIdx, xIdx, k;
int rows, cols;
int nSrcStep;
BYTE* pSrcData;
UINT32 DstSize;
UINT32 SrcFormat;
BITMAP_DATA* bitmap;
@ -649,25 +798,8 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface*
else
shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR);
pSrcData = surface->data;
nSrcStep = surface->scanline;
SrcFormat = PIXEL_FORMAT_RGB32;
if (server->shareSubRect)
{
int subX, subY;
int subWidth, subHeight;
subX = server->subRect.left;
subY = server->subRect.top;
subWidth = server->subRect.right - server->subRect.left;
subHeight = server->subRect.bottom - server->subRect.top;
nXSrc -= subX;
nYSrc -= subY;
pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
}
if ((nXSrc % 4) != 0)
{
nWidth += (nXSrc % 4);
@ -827,7 +959,7 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface*
return 1;
}
int shadow_client_send_surface_update(rdpShadowClient* client)
static int shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
{
int status = -1;
int nXSrc, nYSrc;
@ -840,6 +972,11 @@ int shadow_client_send_surface_update(rdpShadowClient* client)
REGION16 invalidRegion;
RECTANGLE_16 surfaceRect;
const RECTANGLE_16* extents;
BYTE* pSrcData;
int nSrcStep;
int index;
int numRects = 0;
const RECTANGLE_16* rects;
context = (rdpContext*) client;
settings = context->settings;
@ -856,6 +993,12 @@ int shadow_client_send_surface_update(rdpShadowClient* client)
LeaveCriticalSection(&(client->lock));
rects = region16_rects(&(surface->invalidRegion), &numRects);
for (index = 0; index < numRects; index++)
{
region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]);
}
surfaceRect.left = 0;
surfaceRect.top = 0;
surfaceRect.right = surface->width;
@ -870,27 +1013,63 @@ int shadow_client_send_surface_update(rdpShadowClient* client)
if (region16_is_empty(&invalidRegion))
{
/* No image region need to be updated */
region16_uninit(&invalidRegion);
return 1;
}
extents = region16_extents(&invalidRegion);
nXSrc = extents->left - 0;
nYSrc = extents->top - 0;
nXSrc = extents->left;
nYSrc = extents->top;
nWidth = extents->right - extents->left;
nHeight = extents->bottom - extents->top;
pSrcData = surface->data;
nSrcStep = surface->scanline;
/* Move to new pSrcData / nXSrc / nYSrc according to sub rect */
if (server->shareSubRect)
{
int subX, subY;
subX = server->subRect.left;
subY = server->subRect.top;
nXSrc -= subX;
nYSrc -= subY;
pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
}
//WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d",
// nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
if (settings->RemoteFxCodec || settings->NSCodec)
if (settings->SupportGraphicsPipeline &&
settings->GfxH264 &&
pStatus->gfxOpened)
{
status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight);
/* GFX/h264 always full screen encoded */
nWidth = settings->DesktopWidth;
nHeight = settings->DesktopHeight;
/* Create primary surface if have not */
if (!pStatus->gfxSurfaceCreated)
{
/* Only init surface when we have h264 supported */
shadow_client_rdpgfx_new_surface(client);
shadow_client_rdpgfx_reset_graphic(client);
pStatus->gfxSurfaceCreated = TRUE;
}
status = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth, nHeight);
}
else if (settings->RemoteFxCodec || settings->NSCodec)
{
status = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight);
}
else
{
status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight);
status = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight);
}
region16_uninit(&invalidRegion);
@ -898,27 +1077,67 @@ int shadow_client_send_surface_update(rdpShadowClient* client)
return status;
}
static void shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
{
rdpContext* context;
rdpSettings* settings;
rdpShadowServer* server;
freerdp_peer* peer;
server = client->server;
context = (rdpContext*) client;
peer = context->peer;
settings = context->settings;
/**
* Unset client activated flag to avoid sending update message during
* resize. DesktopResize will reactive the client and
* shadow_client_activate would be invoked later.
*/
client->activated = FALSE;
/* Close Gfx surfaces */
if (pStatus->gfxSurfaceCreated)
{
shadow_client_rdpgfx_release_surface(client);
pStatus->gfxSurfaceCreated = FALSE;
}
/* Send Resize */
peer->update->DesktopResize(peer->update->context); // update_send_desktop_resize
/* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
EnterCriticalSection(&(client->lock));
region16_clear(&(client->invalidRegion));
LeaveCriticalSection(&(client->lock));
WLog_INFO(TAG, "Client from %s is resized (%dx%d@%d)",
peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
}
static INLINE void shadow_client_no_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
{
rdpShadowServer* server;
rdpShadowSurface* surface;
server = client->server;
surface = client->inLobby ? server->lobby : server->surface;
shadow_client_surface_update(client, &(surface->invalidRegion));
}
int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
{
int index;
int numRects = 0;
const RECTANGLE_16* rects;
EnterCriticalSection(&(client->lock));
rects = region16_rects(region, &numRects);
for (index = 0; index < numRects; index++)
{
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
}
LeaveCriticalSection(&(client->lock));
shadow_client_mark_invalid(client, numRects, rects);
return 1;
}
int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
{
rdpContext* context = (rdpContext*) client;
rdpUpdate* update = context->update;
@ -1013,7 +1232,7 @@ int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* m
return 1;
}
void* shadow_client_thread(rdpShadowClient* client)
static void* shadow_client_thread(rdpShadowClient* client)
{
DWORD status;
DWORD nCount;
@ -1034,6 +1253,11 @@ void* shadow_client_thread(rdpShadowClient* client)
rdpShadowEncoder* encoder;
rdpShadowSubsystem* subsystem;
wMessageQueue* MsgQueue = client->MsgQueue;
/* This should only be visited in client thread */
SHADOW_GFX_STATUS gfxstatus;
gfxstatus.gfxOpened = FALSE;
gfxstatus.gfxSurfaceCreated = FALSE;
server = client->server;
screen = server->screen;
@ -1080,50 +1304,35 @@ void* shadow_client_thread(rdpShadowClient* client)
if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
{
if (client->activated)
/* The UpdateEvent means to start sending current frame. It is
* triggered from subsystem implementation and it should ensure
* that the screen and primary surface meta data (width, height,
* scanline, invalid region, etc) is not changed until it is reset
* (at shadow_multiclient_consume). As best practice, subsystem
* implementation should invoke shadow_subsystem_frame_update which
* triggers the event and then wait for completion */
if (client->activated && !client->suppressOutput)
{
int index;
int numRects = 0;
const RECTANGLE_16* rects;
int width, height;
/* Send screen update or resize to this client */
/* Check resize */
shadow_client_calc_desktop_size(server, &width, &height);
if (settings->DesktopWidth != (UINT32)width || settings->DesktopHeight != (UINT32)height)
if (shadow_client_recalc_desktop_size(client))
{
/* Screen size changed, do resize */
settings->DesktopWidth = width;
settings->DesktopHeight = height;
/**
* Unset client activated flag to avoid sending update message during
* resize. DesktopResize will reactive the client and
* shadow_client_activate would be invoked later.
*/
client->activated = FALSE;
/* Send Resize */
peer->update->DesktopResize(peer->update->context); // update_send_desktop_resize
/* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
region16_clear(&(client->invalidRegion));
WLog_ERR(TAG, "Client from %s is resized (%dx%d@%d)",
peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
shadow_client_send_resize(client, &gfxstatus);
}
else
{
/* Send frame */
rects = region16_rects(&(subsystem->invalidRegion), &numRects);
for (index = 0; index < numRects; index++)
{
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
}
shadow_client_send_surface_update(client);
shadow_client_send_surface_update(client, &gfxstatus);
}
}
else
{
/* Our client don't receive graphic updates. Just save the invalid region */
shadow_client_no_surface_update(client, &gfxstatus);
}
/*
* The return value of shadow_multiclient_consume is whether or not the subscriber really consumes the event.
@ -1139,6 +1348,38 @@ void* shadow_client_thread(rdpShadowClient* client)
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
break;
}
if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, "drdynvc"))
{
/* Dynamic channel status may have been changed after processing */
if (((WTSVirtualChannelManager*)(client->vcm))->drdynvc_state == DRDYNVC_STATE_NONE)
{
/* Call this routine to Initialize drdynvc channel */
if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
{
WLog_ERR(TAG, "Failed to initialize drdynvc channel");
break;
}
}
else if (((WTSVirtualChannelManager*)(client->vcm))->drdynvc_state == DRDYNVC_STATE_READY)
{
/* Init RDPGFX dynamic channel */
if (settings->SupportGraphicsPipeline && client->rdpgfx &&
!gfxstatus.gfxOpened)
{
if (!client->rdpgfx->Open(client->rdpgfx))
{
WLog_ERR(TAG, "Failed to open GraphicsPipeline");
settings->SupportGraphicsPipeline = FALSE;
}
client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge;
gfxstatus.gfxOpened = TRUE;
WLog_INFO(TAG, "Gfx Pipeline Opened");
}
}
}
}
if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
@ -1220,6 +1461,14 @@ void* shadow_client_thread(rdpShadowClient* client)
}
/* Free channels early because we establish channels in post connect */
if (gfxstatus.gfxOpened)
{
if (gfxstatus.gfxSurfaceCreated)
{
shadow_client_rdpgfx_release_surface(client);
}
(void)client->rdpgfx->Close(client->rdpgfx);
}
shadow_client_channels_free(client);
if (UpdateSubscriber)

View File

@ -130,9 +130,6 @@ int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
{
rdpContext* context = (rdpContext*) encoder->client;
rdpSettings* settings = context->settings;
if (!encoder->rfx)
encoder->rfx = rfx_context_new(TRUE);
@ -148,12 +145,6 @@ int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
rfx_context_set_pixel_format(encoder->rfx, RDP_PIXEL_FORMAT_B8G8R8A8);
encoder->fps = 16;
encoder->maxFps = 32;
encoder->frameId = 0;
encoder->lastAckframeId = 0;
encoder->frameAck = settings->SurfaceFrameMarkerEnabled;
encoder->codecs |= FREERDP_CODEC_REMOTEFX;
return 1;
@ -172,23 +163,24 @@ int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
encoder->nsc = nsc_context_new();
if (!encoder->nsc)
return -1;
goto fail;
nsc_context_set_pixel_format(encoder->nsc, RDP_PIXEL_FORMAT_B8G8R8A8);
encoder->fps = 16;
encoder->maxFps = 32;
encoder->frameId = 0;
encoder->lastAckframeId = 0;
encoder->frameAck = settings->SurfaceFrameMarkerEnabled;
if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
goto fail;
encoder->nsc->ColorLossLevel = settings->NSCodecColorLossLevel;
encoder->nsc->ChromaSubsamplingLevel = settings->NSCodecAllowSubsampling ? 1 : 0;
encoder->nsc->DynamicColorFidelity = settings->NSCodecAllowDynamicColorFidelity;
nsc_context_set_pixel_format(encoder->nsc, RDP_PIXEL_FORMAT_B8G8R8A8);
encoder->codecs |= FREERDP_CODEC_NSCODEC;
return 1;
fail:
nsc_context_free(encoder->nsc);
return -1;
}
int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
@ -209,11 +201,18 @@ int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
}
if (!encoder->planar)
return -1;
goto fail;
if (!freerdp_bitmap_planar_context_reset(encoder->planar))
goto fail;
encoder->codecs |= FREERDP_CODEC_PLANAR;
return 1;
fail:
freerdp_bitmap_planar_context_free(encoder->planar);
return -1;
}
int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
@ -222,11 +221,38 @@ int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
encoder->interleaved = bitmap_interleaved_context_new(TRUE);
if (!encoder->interleaved)
return -1;
goto fail;
if (!bitmap_interleaved_context_reset(encoder->interleaved))
goto fail;
encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
return 1;
fail:
bitmap_interleaved_context_free(encoder->interleaved);
return -1;
}
int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
{
if (!encoder->h264)
encoder->h264 = h264_context_new(TRUE);
if (!encoder->h264)
goto fail;
if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
goto fail;
encoder->codecs |= FREERDP_CODEC_AVC420;
return 1;
fail:
h264_context_free(encoder->h264);
return -1;
}
int shadow_encoder_init(rdpShadowEncoder* encoder)
@ -300,6 +326,19 @@ int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
return 1;
}
int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
{
if (encoder->h264)
{
h264_context_free(encoder->h264);
encoder->h264= NULL;
}
encoder->codecs &= ~FREERDP_CODEC_AVC420;
return 1;
}
int shadow_encoder_uninit(rdpShadowEncoder* encoder)
{
shadow_encoder_uninit_grid(encoder);
@ -330,6 +369,11 @@ int shadow_encoder_uninit(rdpShadowEncoder* encoder)
shadow_encoder_uninit_interleaved(encoder);
}
if (encoder->codecs & FREERDP_CODEC_AVC420)
{
shadow_encoder_uninit_h264(encoder);
}
return 1;
}
@ -337,6 +381,8 @@ int shadow_encoder_reset(rdpShadowEncoder* encoder)
{
int status;
UINT32 codecs = encoder->codecs;
rdpContext* context = (rdpContext*) encoder->client;
rdpSettings* settings = context->settings;
status = shadow_encoder_uninit(encoder);
@ -353,6 +399,12 @@ int shadow_encoder_reset(rdpShadowEncoder* encoder)
if (status < 0)
return -1;
encoder->fps = 16;
encoder->maxFps = 32;
encoder->frameId = 0;
encoder->lastAckframeId = 0;
encoder->frameAck = settings->SurfaceFrameMarkerEnabled;
return 1;
}
@ -392,6 +444,14 @@ int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
return -1;
}
if ((codecs & FREERDP_CODEC_AVC420) && !(encoder->codecs & FREERDP_CODEC_AVC420))
{
status = shadow_encoder_init_h264(encoder);
if (status < 0)
return -1;
}
return 1;
}

View File

@ -49,6 +49,7 @@ struct rdp_shadow_encoder
NSC_CONTEXT* nsc;
BITMAP_PLANAR_CONTEXT* planar;
BITMAP_INTERLEAVED_CONTEXT* interleaved;
H264_CONTEXT* h264;
int fps;
int maxFps;

View File

@ -0,0 +1,87 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <freerdp/log.h>
#include "shadow.h"
#include "shadow_rdpgfx.h"
#define TAG SERVER_TAG("shadow")
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rdpgfx_caps_advertise(RdpgfxServerContext* context, RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
{
UINT16 index;
RDPGFX_CAPS_CONFIRM_PDU pdu;
rdpSettings* settings = context->rdpcontext->settings;
UINT32 flags = 0;
for (index = 0; index < capsAdvertise->capsSetCount; index++)
{
pdu.capsSet = &(capsAdvertise->capsSets[index]);
if (pdu.capsSet->version == RDPGFX_CAPVERSION_81)
{
if (settings)
{
flags = pdu.capsSet->flags;
settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
}
return context->CapsConfirm(context, &pdu);
}
}
return CHANNEL_RC_UNSUPPORTED_VERSION;
}
int shadow_client_rdpgfx_init(rdpShadowClient* client)
{
RdpgfxServerContext* rdpgfx;
rdpgfx = client->rdpgfx = rdpgfx_server_context_new(client->vcm);
if (!rdpgfx)
{
return 0;
}
rdpgfx->rdpcontext = &client->context;
rdpgfx->custom = client;
rdpgfx->CapsAdvertise = rdpgfx_caps_advertise;
return 1;
}
void shadow_client_rdpgfx_uninit(rdpShadowClient* client)
{
if (client->rdpgfx)
{
rdpgfx_server_context_free(client->rdpgfx);
client->rdpgfx = NULL;
}
}

View File

@ -0,0 +1,38 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_SHADOW_SERVER_RDPGFX_H
#define FREERDP_SHADOW_SERVER_RDPGFX_H
#include <freerdp/server/shadow.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#ifdef __cplusplus
extern "C" {
#endif
int shadow_client_rdpgfx_init(rdpShadowClient* client);
void shadow_client_rdpgfx_uninit(rdpShadowClient* client);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SHADOW_SERVER_RDPGFX_H */

View File

@ -86,8 +86,6 @@ int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server
if (!(subsystem->updateEvent = shadow_multiclient_new()))
goto fail;
region16_init(&(subsystem->invalidRegion));
if ((status = subsystem->ep.Init(subsystem)) >= 0)
return status;
@ -141,9 +139,6 @@ void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem)
shadow_multiclient_free(subsystem->updateEvent);
subsystem->updateEvent = NULL;
}
if (subsystem->invalidRegion.data)
region16_uninit(&(subsystem->invalidRegion));
}
int shadow_subsystem_start(rdpShadowSubsystem* subsystem)