rdpgfx: Implementation for server side channel
server/shadow: support h264 codec with gfx channel
This commit is contained in:
parent
5b2455f314
commit
746a754244
@ -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()
|
||||
|
@ -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(..)
|
||||
|
||||
|
@ -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)
|
34
channels/rdpgfx/server/CMakeLists.txt
Normal file
34
channels/rdpgfx/server/CMakeLists.txt
Normal 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")
|
1239
channels/rdpgfx/server/rdpgfx_main.c
Normal file
1239
channels/rdpgfx/server/rdpgfx_main.c
Normal file
File diff suppressed because it is too large
Load Diff
36
channels/rdpgfx/server/rdpgfx_main.h
Normal file
36
channels/rdpgfx/server/rdpgfx_main.h
Normal 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 */
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
96
include/freerdp/server/rdpgfx.h
Normal file
96
include/freerdp/server/rdpgfx.h
Normal 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 */
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "shadow_remdesk.h"
|
||||
#include "shadow_rdpsnd.h"
|
||||
#include "shadow_audin.h"
|
||||
#include "shadow_rdpgfx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -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, ®ion, area, 1);
|
||||
shadow_client_mark_invalid(client, 1, ®ion);
|
||||
}
|
||||
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 = ®ionRect;
|
||||
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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
87
server/shadow/shadow_rdpgfx.c
Normal file
87
server/shadow/shadow_rdpgfx.c
Normal 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;
|
||||
}
|
||||
}
|
38
server/shadow/shadow_rdpgfx.h
Normal file
38
server/shadow/shadow_rdpgfx.h
Normal 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 */
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user