Merge pull request #3316 from realjiangms/server_gfx

rdpgfx: Implementation for server side channel
This commit is contained in:
David Fort 2016-08-24 11:08:00 +02:00 committed by GitHub
commit 5394a0425f
35 changed files with 3146 additions and 410 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

@ -57,7 +57,7 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s,
Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * sizeof(RECTANGLE_16)))
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8))
{
WLog_ERR(TAG, "not enough data!");
goto error_out;

View File

@ -457,7 +457,7 @@ static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStre
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
UINT error = CHANNEL_RC_OK;
if (Stream_GetRemainingLength(s) < 8)
if (Stream_GetRemainingLength(s) < RDPGFX_START_FRAME_PDU_SIZE)
{
WLog_ERR(TAG, "not enough data!");
return ERROR_INVALID_DATA;
@ -494,7 +494,7 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
UINT error = CHANNEL_RC_OK;
if (Stream_GetRemainingLength(s) < 4)
if (Stream_GetRemainingLength(s) < RDPGFX_END_FRAME_PDU_SIZE)
{
WLog_ERR(TAG, "not enough data!");
return ERROR_INVALID_DATA;
@ -550,7 +550,7 @@ static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
UINT error;
if (Stream_GetRemainingLength(s) < 17)
if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE)
{
WLog_ERR(TAG, "not enough data!");
return ERROR_INVALID_DATA;
@ -615,7 +615,7 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
UINT error = CHANNEL_RC_OK;
if (Stream_GetRemainingLength(s) < 13)
if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE)
{
WLog_ERR(TAG, "not enough data!");
return ERROR_INVALID_DATA;

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 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.
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,40 @@
/**
* 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;
BOOL ownThread;
HANDLE thread;
HANDLE stopEvent;
HANDLE channelEvent;
void* rdpgfx_channel;
DWORD SessionId;
wStream* input_stream;
BOOL isOpened;
BOOL isReady;
};
#endif /* FREERDP_CHANNEL_RDPGFX_SERVER_MAIN_H */

View File

@ -49,6 +49,7 @@
#include <freerdp/server/drdynvc.h>
#include <freerdp/server/remdesk.h>
#include <freerdp/server/encomsp.h>
#include <freerdp/server/rdpgfx.h>
void freerdp_channels_dummy()
{
@ -79,6 +80,8 @@ void freerdp_channels_dummy()
encomsp_server_context_new(NULL);
encomsp_server_context_free(NULL);
rdpgfx_server_context_new(NULL);
rdpgfx_server_context_free(NULL);
}
/**

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
@ -142,6 +143,8 @@ typedef struct _RDPGFX_CAPSET_VERSION10 RDPGFX_CAPSET_VERSION10;
#define RDPGFX_CODECID_ALPHA 0x000C
#define RDPGFX_CODECID_AVC444 0x000E
#define RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE 17
struct _RDPGFX_WIRE_TO_SURFACE_PDU_1
{
UINT16 surfaceId;
@ -156,6 +159,8 @@ typedef struct _RDPGFX_WIRE_TO_SURFACE_PDU_1 RDPGFX_WIRE_TO_SURFACE_PDU_1;
#define RDPGFX_CODECID_CAPROGRESSIVE 0x0009
#define RDPGFX_CODECID_CAPROGRESSIVE_V2 0x000D
#define RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE 13
struct _RDPGFX_WIRE_TO_SURFACE_PDU_2
{
UINT16 surfaceId;
@ -250,6 +255,8 @@ struct _RDPGFX_DELETE_SURFACE_PDU
};
typedef struct _RDPGFX_DELETE_SURFACE_PDU RDPGFX_DELETE_SURFACE_PDU;
#define RDPGFX_START_FRAME_PDU_SIZE 8
struct _RDPGFX_START_FRAME_PDU
{
UINT32 timestamp;
@ -257,6 +264,8 @@ struct _RDPGFX_START_FRAME_PDU
};
typedef struct _RDPGFX_START_FRAME_PDU RDPGFX_START_FRAME_PDU;
#define RDPGFX_END_FRAME_PDU_SIZE 4
struct _RDPGFX_END_FRAME_PDU
{
UINT32 frameId;
@ -372,6 +381,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

@ -43,6 +43,13 @@
extern "C" {
#endif
enum
{
DRDYNVC_STATE_NONE = 0,
DRDYNVC_STATE_INITIALIZED = 1,
DRDYNVC_STATE_READY = 2
};
/**
* WTSVirtualChannelManager functions are FreeRDP extensions to the API.
*/
@ -51,6 +58,7 @@ FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(HANDLE hServer, void*
FREERDP_API BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer);
FREERDP_API HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer);
FREERDP_API BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name);
FREERDP_API BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer);
/**
* Extended FreeRDP WTS functions for channel handling

View File

@ -28,12 +28,16 @@
#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;
BYTE* pbInputCurrent;
BYTE* pbInputEnd;
const BYTE* pbInputCurrent;
const BYTE* pbInputEnd;
UINT32 bits;
UINT32 cBitsRemaining;
@ -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_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags);
FREERDP_API void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush);

View File

@ -0,0 +1,100 @@
/**
* 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(*psRdpgfxResetGraphics)(RdpgfxServerContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics);
typedef UINT(*psRdpgfxStartFrame)(RdpgfxServerContext* context, RDPGFX_START_FRAME_PDU* startFrame);
typedef UINT(*psRdpgfxEndFrame)(RdpgfxServerContext* context, RDPGFX_END_FRAME_PDU* endFrame);
typedef UINT(*psRdpgfxSurfaceCommand)(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd);
typedef UINT(*psRdpgfxSurfaceFrameCommand)(RdpgfxServerContext* context, RDPGFX_SURFACE_COMMAND* cmd, RDPGFX_START_FRAME_PDU* startFrame, RDPGFX_END_FRAME_PDU* endFrame);
typedef UINT(*psRdpgfxDeleteEncodingContext)(RdpgfxServerContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext);
typedef UINT(*psRdpgfxCreateSurface)(RdpgfxServerContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface);
typedef UINT(*psRdpgfxDeleteSurface)(RdpgfxServerContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface);
typedef UINT(*psRdpgfxSolidFill)(RdpgfxServerContext* context, RDPGFX_SOLID_FILL_PDU* solidFill);
typedef UINT(*psRdpgfxSurfaceToSurface)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface);
typedef UINT(*psRdpgfxSurfaceToCache)(RdpgfxServerContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache);
typedef UINT(*psRdpgfxCacheToSurface)(RdpgfxServerContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface);
typedef UINT(*psRdpgfxCacheImportOffer)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer);
typedef UINT(*psRdpgfxCacheImportReply)(RdpgfxServerContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply);
typedef UINT(*psRdpgfxEvictCacheEntry)(RdpgfxServerContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry);
typedef UINT(*psRdpgfxMapSurfaceToOutput)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput);
typedef UINT(*psRdpgfxMapSurfaceToWindow)(RdpgfxServerContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow);
typedef UINT(*psRdpgfxCapsAdvertise)(RdpgfxServerContext* context, RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise);
typedef UINT(*psRdpgfxCapsConfirm)(RdpgfxServerContext* context, RDPGFX_CAPS_CONFIRM_PDU* capsConfirm);
typedef UINT(*psRdpgfxFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge);
typedef UINT(*psRdpgfxQoeFrameAcknowledge)(RdpgfxServerContext* context, RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge);
struct _rdpgfx_server_context
{
HANDLE vcm;
void* custom;
psRdpgfxServerOpen Open;
psRdpgfxServerClose Close;
psRdpgfxResetGraphics ResetGraphics;
psRdpgfxStartFrame StartFrame;
psRdpgfxEndFrame EndFrame;
psRdpgfxSurfaceCommand SurfaceCommand;
psRdpgfxSurfaceFrameCommand SurfaceFrameCommand;
psRdpgfxDeleteEncodingContext DeleteEncodingContext;
psRdpgfxCreateSurface CreateSurface;
psRdpgfxDeleteSurface DeleteSurface;
psRdpgfxSolidFill SolidFill;
psRdpgfxSurfaceToSurface SurfaceToSurface;
psRdpgfxSurfaceToCache SurfaceToCache;
psRdpgfxCacheToSurface CacheToSurface;
psRdpgfxCacheImportOffer CacheImportOffer;
psRdpgfxCacheImportReply CacheImportReply;
psRdpgfxEvictCacheEntry EvictCacheEntry;
psRdpgfxMapSurfaceToOutput MapSurfaceToOutput;
psRdpgfxMapSurfaceToWindow MapSurfaceToWindow;
psRdpgfxCapsAdvertise CapsAdvertise;
psRdpgfxCapsConfirm CapsConfirm;
psRdpgfxFrameAcknowledge FrameAcknowledge;
psRdpgfxQoeFrameAcknowledge 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);
FREERDP_API HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context);
FREERDP_API UINT rdpgfx_server_handle_messages(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
@ -124,6 +127,14 @@ struct rdp_shadow_server
BOOL authentication;
int selectedMonitor;
RECTANGLE_16 subRect;
/* Codec settings */
RLGR_MODE rfxMode;
H264_RATECONTROL_MODE h264RateControlMode;
UINT32 h264BitRate;
FLOAT h264FrameRate;
UINT32 h264QP;
char* ipcSocket;
char* ConfigPath;
char* CertificateFile;
@ -169,9 +180,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 +215,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:
*
@ -105,7 +108,7 @@ static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] =
_zgfx->bits = _zgfx->BitsCurrent >> _zgfx->cBitsCurrent; \
_zgfx->BitsCurrent &= ((1 << _zgfx->cBitsCurrent) - 1);
void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* zgfx, BYTE* src, UINT32 count)
void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* zgfx, const BYTE* src, UINT32 count)
{
UINT32 front;
UINT32 residue;
@ -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, const BYTE* pbSegment, UINT32 cbSegment)
{
BYTE c;
BYTE flags;
@ -322,7 +325,7 @@ int zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, UINT32 cbSegmen
return 1;
}
int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags)
int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags)
{
int status;
BYTE descriptor;
@ -383,11 +386,120 @@ 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, const 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, const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags)
{
int fragment;
UINT16 maxLength;
UINT32 totalLength;
size_t posSegmentCount = 0;
const BYTE* pSrcData;
int status = 0;
maxLength = ZGFX_SEGMENTED_MAXSIZE;
totalLength = uncompressedSize;
pSrcData = pUncompressed;
for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
{
UINT32 SrcSize;
size_t posDstSize;
size_t posDataStart;
UINT32 DstSize;
SrcSize = (totalLength > maxLength) ? maxLength : totalLength;
posDstSize = 0;
totalLength -= SrcSize;
/* Ensure we have enough space for headers */
if (!Stream_EnsureRemainingCapacity(sDst, 12))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return -1;
}
if (fragment == 0)
{
/* First fragment */
/* descriptor (1 byte) */
Stream_Write_UINT8(sDst, (totalLength == 0) ?
ZGFX_SEGMENTED_SINGLE : ZGFX_SEGMENTED_MULTIPART);
if (totalLength > 0)
{
posSegmentCount = Stream_GetPosition(sDst); /* segmentCount (2 bytes) */
Stream_Seek(sDst, 2);
Stream_Write_UINT32(sDst, uncompressedSize); /* uncompressedSize (4 bytes) */
}
}
if (fragment > 0 || totalLength > 0)
{
/* Multipart */
posDstSize = Stream_GetPosition(sDst); /* size (4 bytes) */
Stream_Seek(sDst, 4);
}
posDataStart = Stream_GetPosition(sDst);
if ((status = zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags)) < 0)
{
return status;
}
if (posDstSize)
{
/* Fill segment data size */
DstSize = Stream_GetPosition(sDst) - posDataStart;
Stream_SetPosition(sDst, posDstSize);
Stream_Write_UINT32(sDst, DstSize);
Stream_SetPosition(sDst, posDataStart + DstSize);
}
pSrcData += SrcSize;
}
Stream_SealLength(sDst);
/* fill back segmentCount */
if (posSegmentCount)
{
Stream_SetPosition(sDst, posSegmentCount);
Stream_Write_UINT16(sDst, fragment);
Stream_SetPosition(sDst, Stream_Length(sDst));
}
return status;
}
int zgfx_compress(ZGFX_CONTEXT* zgfx, const 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

@ -557,6 +557,13 @@ BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name)
return wts_get_joined_channel_by_name(vcm->rdp->mcs, name) == NULL ? FALSE : TRUE;
}
BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer)
{
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*) hServer;
return vcm->drdynvc_state;
}
UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name)
{
rdpMcsChannel* channel;
@ -1205,6 +1212,7 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer,
BYTE* buffer;
UINT32 length;
UINT32 written;
UINT32 totalWritten = 0;
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
BOOL ret = TRUE;
@ -1222,6 +1230,8 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer,
}
CopyMemory(buffer, Buffer, length);
totalWritten = Length;
ret = wts_queue_send_item(channel, buffer, length);
}
else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
@ -1270,13 +1280,14 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer,
Length -= written;
Buffer += written;
totalWritten += written;
ret = wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, length);
}
}
if (pBytesWritten)
*pBytesWritten = Length;
*pBytesWritten = totalWritten;
return ret;
}

View File

@ -47,13 +47,6 @@ enum
RDP_PEER_CHANNEL_TYPE_DVC = 1
};
enum
{
DRDYNVC_STATE_NONE = 0,
DRDYNVC_STATE_INITIALIZED = 1,
DRDYNVC_STATE_READY = 2
};
enum
{
DVC_OPEN_STATE_NONE = 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;
@ -316,9 +317,6 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa
if (count < 1)
return;
if ((count == 1) && subsystem->suppressOutput)
return;
mac_shadow_capture_get_dirty_region(subsystem);
surfaceRect.left = 0;
@ -326,11 +324,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;
@ -359,7 +357,9 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa
count = ArrayList_Count(server->clients);
EnterCriticalSection(&(surface->lock));
shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem);
LeaveCriticalSection(&(surface->lock));
if (count == 1)
{
@ -375,7 +375,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)
@ -444,48 +444,15 @@ int mac_shadow_screen_grab(macShadowSubsystem* subsystem)
int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message)
{
rdpShadowServer* server = subsystem->server;
rdpShadowSurface* surface = server->surface;
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:
EnterCriticalSection(&(surface->lock));
shadow_subsystem_frame_update((rdpShadowSubsystem *)subsystem);
LeaveCriticalSection(&(surface->lock));
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" {

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@
extern "C" {
#endif
int shadow_client_surface_update(rdpShadowClient* client, REGION16* region);
BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region);
BOOL shadow_client_accepted(freerdp_listener* instance, freerdp_peer* client);
#ifdef __cplusplus

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);
@ -142,18 +139,10 @@ int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height))
goto fail;
encoder->rfx->mode = RLGR3;
encoder->rfx->width = encoder->width;
encoder->rfx->height = encoder->height;
encoder->rfx->mode = encoder->server->rfxMode;
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 +161,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 +199,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 +219,43 @@ 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->h264->RateControlMode = encoder->server->h264RateControlMode;
encoder->h264->BitRate = encoder->server->h264BitRate;
encoder->h264->FrameRate = encoder->server->h264FrameRate;
encoder->h264->QP = encoder->server->h264QP;
encoder->codecs |= FREERDP_CODEC_AVC420;
return 1;
fail:
h264_context_free(encoder->h264);
return -1;
}
int shadow_encoder_init(rdpShadowEncoder* encoder)
@ -300,6 +329,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 +372,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 +384,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 +402,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 +447,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,98 @@
/**
* 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_10)
{
if (settings)
{
flags = pdu.capsSet->flags;
settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
settings->GfxH264 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
}
return context->CapsConfirm(context, &pdu);
}
else 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

@ -769,6 +769,12 @@ rdpShadowServer* shadow_server_new()
server->mayView = TRUE;
server->mayInteract = TRUE;
server->rfxMode = RLGR3;
server->h264RateControlMode = H264_RATECONTROL_VBR;
server->h264BitRate = 1000000;
server->h264FrameRate = 30;
server->h264QP = 0;
server->authentication = FALSE;
server->settings = freerdp_settings_new(FREERDP_SETTINGS_SERVER_MODE);

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)