Merge pull request #705 from awakecoding/windows

Windows FreeRDP Server RemoteFX Encoding
This commit is contained in:
Marc-André Moreau 2012-08-23 12:43:32 -07:00
commit 577b8e30eb
9 changed files with 1509 additions and 379 deletions

View File

@ -20,18 +20,28 @@
add_executable(wfreerdp-server
wf_input.c
wf_input.h
wf_mirage.c
wf_mirage.h
wf_peer.c
wf_peer.h
wf_info.c
wf_info.h
wfreerdp.c
wfreerdp.h)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(wfreerdp-server freerdp)
else()
target_link_libraries(wfreerdp-server
freerdp-core
freerdp-utils
freerdp-codec
freerdp-channels)
endif()
else()
target_link_libraries(wfreerdp-server
freerdp-core
freerdp-utils
freerdp-codec
freerdp-channels)
endif()

302
server/Windows/wf_info.c Normal file
View File

@ -0,0 +1,302 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* FreeRDP Windows Server
*
* Copyright 2012 Corey Clayton <can.of.tuna@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.
*/
#include <stdlib.h>
#include <winpr/tchar.h>
#include <winpr/windows.h>
#include "wf_info.h"
#include "wf_mirage.h"
wfInfo * wf_info_init(wfInfo * info)
{
if(!info)
{
info = (wfInfo*)malloc(sizeof(wfInfo)); //free this on shutdown
memset(info, 0, sizeof(wfInfo));
info->mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (info->mutex == NULL)
{
_tprintf(_T("CreateMutex error: %d\n"), GetLastError());
}
info->encodeMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (info->encodeMutex == NULL)
{
_tprintf(_T("CreateMutex error: %d\n"), GetLastError());
}
info->can_send_mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (info->can_send_mutex == NULL)
{
_tprintf(_T("CreateMutex error: %d\n"), GetLastError());
}
}
return info;
}
void wf_info_mirror_init(wfInfo * info, wfPeerContext* context)
{
DWORD dRes;
dRes = WaitForSingleObject(
info->mutex, // handle to mutex
INFINITE); // no time-out interval
switch(dRes)
{
case WAIT_OBJECT_0:
if(info->subscribers == 0)
{
//only the first peer needs to call this.
context->wfInfo = info;
wf_check_disp_devices(context->wfInfo);
wf_disp_device_set_attatch(context->wfInfo, 1);
wf_update_mirror_drv(context->wfInfo, 0);
wf_map_mirror_mem(context->wfInfo);
context->rfx_context = rfx_context_new();
context->rfx_context->mode = RLGR3;
context->rfx_context->width = context->wfInfo->width;
context->rfx_context->height = context->wfInfo->height;
rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
context->s = stream_new(65536);
printf("Start Encoder\n");
ReleaseMutex(info->encodeMutex);
}
++info->subscribers;
if (! ReleaseMutex(info->mutex))
{
_tprintf(_T("Error releasing mutex\n"));
}
break;
default:
_tprintf(_T("Error waiting for mutex: %d\n"), dRes);
}
}
//todo: i think i can replace all the context->info here with info
//in fact it may not even care about subscribers
void wf_info_subscriber_release(wfInfo* info, wfPeerContext* context)
{
DWORD dRes;
WaitForSingleObject(info->mutex, INFINITE);
if (context && (info->subscribers == 1))
{
dRes = WaitForSingleObject(info->encodeMutex, INFINITE);
switch (dRes)
{
// The thread got ownership of the mutex
case WAIT_OBJECT_0:
--info->subscribers;
//only the last peer needs to call this
wf_mirror_cleanup(context->wfInfo);
wf_disp_device_set_attatch(context->wfInfo, 0);
wf_update_mirror_drv(context->wfInfo, 1);
stream_free(context->s);
rfx_context_free(context->rfx_context);
printf("Stop encoder\n");
break;
// The thread got ownership of an abandoned mutex
// The database is in an indeterminate state
default:
printf("wf_info_subscriber_release: Something else happened!!! dRes = %d\n", dRes);
}
}
else
{
--info->subscribers;
}
ReleaseMutex(info->mutex);
/***************
Note: if we released the last subscriber,
block the encoder until next subscriber
***************/
}
BOOL wf_info_has_subscribers(wfInfo* info)
{
int subs;
WaitForSingleObject(info->mutex, INFINITE);
subs = info->subscribers;
ReleaseMutex(info->mutex);
if(info->subscribers > 0)
return true;
return false;
}
BOOL wf_info_have_updates(wfInfo* info)
{
BOOL ret;
ret = true;
WaitForSingleObject(info->mutex, INFINITE);
if(info->nextUpdate == info->lastUpdate)
ret = false;
ReleaseMutex(info->mutex);
return ret;
}
void wf_info_updated(wfInfo* info)
{
WaitForSingleObject(info->mutex, INFINITE);
info->lastUpdate = info->nextUpdate;
ReleaseMutex(info->mutex);
}
void wf_info_update_changes(wfInfo* info)
{
GETCHANGESBUF* buf;
WaitForSingleObject(info->mutex, INFINITE);
buf = (GETCHANGESBUF*)info->changeBuffer;
info->nextUpdate = buf->buffer->counter;
ReleaseMutex(info->mutex);
}
void wf_info_find_invalid_region(wfInfo* info)
{
int i;
GETCHANGESBUF* buf;
WaitForSingleObject(info->mutex, INFINITE);
buf = (GETCHANGESBUF*)info->changeBuffer;
if(info->enc_data == false)
{
info->invalid_x1 = 1920;//info->width;
info->invalid_x2 = 0;
info->invalid_y1 = 1200;// info->height;
info->invalid_y2 = 0;
}
//printf("\tFIND = (%d, %d), (%d, %d)\n", info->invalid_x1, info->invalid_y1, info->invalid_x2, info->invalid_y2);
for(i = info->lastUpdate; i != info->nextUpdate; i = (i+1) % MAXCHANGES_BUF )
{
/*printf("\t(%d, %d), (%d, %d)\n",
buf->buffer->pointrect[i].rect.left,
buf->buffer->pointrect[i].rect.top,
buf->buffer->pointrect[i].rect.right,
buf->buffer->pointrect[i].rect.bottom);
*/
info->invalid_x1 = min(info->invalid_x1, buf->buffer->pointrect[i].rect.left);
info->invalid_x2 = max(info->invalid_x2, buf->buffer->pointrect[i].rect.right);
info->invalid_y1 = min(info->invalid_y1, buf->buffer->pointrect[i].rect.top);
info->invalid_y2 = max(info->invalid_y2, buf->buffer->pointrect[i].rect.bottom);
}
ReleaseMutex(info->mutex);
}
void wf_info_clear_invalid_region(wfInfo* info)
{
WaitForSingleObject(info->mutex, INFINITE);
info->lastUpdate = info->nextUpdate;
info->invalid_x1 = info->width;
info->invalid_x2 = 0;
info->invalid_y1 = info->height;
info->invalid_y2 = 0;
ReleaseMutex(info->mutex);
}
BOOL wf_info_have_invalid_region(wfInfo* info)
{
if((info->invalid_x1 >= info->invalid_x2) || (info->invalid_y1 >= info->invalid_y2))
return false;
return true;
}
int wf_info_get_height(wfInfo* info)
{
int ret;
WaitForSingleObject(info->mutex, INFINITE);
ret = info->height;
ReleaseMutex(info->mutex);
return ret;
}
int wf_info_get_width(wfInfo* info)
{
int ret;
WaitForSingleObject(info->mutex, INFINITE);
ret = info->width;
ReleaseMutex(info->mutex);
return ret;
}
int wf_info_get_thread_count(wfInfo* info)
{
int ret;
WaitForSingleObject(info->mutex, INFINITE);
ret = info->threadCnt;
ReleaseMutex(info->mutex);
return ret;
}
void wf_info_set_thread_count(wfInfo* info, int count)
{
WaitForSingleObject(info->mutex, INFINITE);
info->threadCnt = count;
ReleaseMutex(info->mutex);
}

76
server/Windows/wf_info.h Normal file
View File

@ -0,0 +1,76 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* FreeRDP Windows Server
*
* Copyright 2012 Corey Clayton <can.of.tuna@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.
*/
#ifndef WF_INFO_H
#define WF_INFO_H
//#include "wfreerdp.h"
struct wf_peer_context;
typedef struct wf_peer_context wfPeerContext;
struct wf_info
{
HDC driverDC;
BOOL activated;
void* changeBuffer;
LPTSTR deviceKey;
TCHAR deviceName[32];
int subscribers;
int threadCnt;
int height;
int width;
int bitsPerPix;
HANDLE mutex, encodeMutex, can_send_mutex;
unsigned long lastUpdate;
unsigned long nextUpdate;
long invalid_x1;
long invalid_y1;
long invalid_x2;
long invalid_y2;
BOOL enc_data;
};
typedef struct wf_info wfInfo;
wfInfo* wf_info_init(wfInfo* info);
void wf_info_mirror_init(wfInfo* info, wfPeerContext* context);
void wf_info_subscriber_release(wfInfo* info, wfPeerContext* context);
int wf_info_get_thread_count(wfInfo* info);
void wf_info_set_thread_count(wfInfo* info, int count);
BOOL wf_info_has_subscribers(wfInfo* info);
BOOL wf_info_have_updates(wfInfo* info);
void wf_info_updated(wfInfo* info);
void wf_info_update_changes(wfInfo* info);
void wf_info_find_invalid_region(wfInfo* info);
void wf_info_clear_invalid_region(wfInfo* info);
BOOL wf_info_have_invalid_region(wfInfo* info);
int wf_info_get_height(wfInfo* info);
int wf_info_get_width(wfInfo* info);
#endif

310
server/Windows/wf_mirage.c Normal file
View File

@ -0,0 +1,310 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* FreeRDP Windows Server
*
* 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.
*/
#include <winpr/tchar.h>
#include <winpr/windows.h>
#include "wf_mirage.h"
#define DEVICE_KEY_PREFIX _T("\\Registry\\Machine\\")
/*
This function will iterate over the loaded display devices until it finds
the mirror device we want to load. If found, it will then copy the registry
key corresponding to the device to the context and returns true. Otherwise
the function returns false.
*/
BOOL wf_check_disp_devices(wfInfo* context)
{
BOOL result, devFound;
DWORD deviceNumber;
DISPLAY_DEVICE deviceInfo;
devFound = false;
deviceNumber = 0;
deviceInfo.cb = sizeof(deviceInfo);
printf("Detecting display devices:\n");
while (result = EnumDisplayDevices(NULL, deviceNumber, &deviceInfo, 0))
{
_tprintf(_T("\t%s\n"), deviceInfo.DeviceString);
if (_tcscmp(deviceInfo.DeviceString, _T("Mirage Driver")) == 0)
{
int deviceKeyLength;
int deviceKeyPrefixLength;
_tprintf(_T("\n\nFound our target of interest!\n"));
deviceKeyPrefixLength = _tcslen(DEVICE_KEY_PREFIX);
if (_tcsncmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0)
{
deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength;
context->deviceKey = (LPTSTR) malloc((deviceKeyLength + 1) * sizeof(TCHAR));
_tcsncpy_s(context->deviceKey, deviceKeyLength + 1,
&deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength);
_tprintf(_T("DeviceKey: %s\n"), context->deviceKey);
}
_tcsncpy_s(context->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName));
return true;
}
deviceNumber++;
}
return false;
}
/*
This function will attempt to access the the windows registry using the device
key stored in the current context. It will attempt to read the value of the
"Attach.ToDesktop" subkey and will return true if the value is already set to
val. If unable to read the subkey, this function will return false. If the
subkey is not set to val it will then attempt to set it to val and return true. If
unsuccessful or an unexpected value is encountered, the function returns
false.
*/
BOOL wf_disp_device_set_attatch(wfInfo* context, DWORD val)
{
LONG status;
DWORD rtype, rdata, rdata_size;
_tprintf(_T("\nOpening registry key %s\n"), context->deviceKey);
rtype = 0;
rdata = 0;
rdata_size = sizeof(rdata);
status = RegGetValue(HKEY_LOCAL_MACHINE, context->deviceKey,
_T("Attach.ToDesktop"), RRF_RT_REG_DWORD, &rtype, &rdata, &rdata_size);
if (status != ERROR_SUCCESS)
{
printf("Failed to read registry value.\n");
printf("operation returned %d\n", status);
return false;
}
_tprintf(_T("type = %04X, data = %04X\n"), rtype, rdata);
if (rdata == (val ^ 1))
{
rdata = val;
status = RegSetKeyValue(HKEY_LOCAL_MACHINE, context->deviceKey,
_T("Attach.ToDesktop"), REG_DWORD, &rdata, rdata_size);
if (status != ERROR_SUCCESS)
{
_tprintf(_T("Failed to write registry value.\n"));
_tprintf(_T("operation returned %d\n"), status);
return false;
}
_tprintf(_T("Wrote subkey \"Attach.ToDesktop\" -> %04X\n\n"), rdata);
}
else if (rdata == val)
{
_tprintf(_T("\"Attach.ToDesktop\" is already set to %04X!\n"), rdata);
}
else
{
_tprintf(_T("An wild value appeared!...\nrdata=%d\n"), rdata);
return false;
}
return true;
}
/*
This function will attempt to apply the currently configured display settings
in the registry to the display driver. It will return true if successful
otherwise it returns false.
If unload is nonzero then the the driver will be asked to remove it self.
*/
BOOL wf_update_mirror_drv(wfInfo* context, int unload)
{
int currentScreenPixHeight, currentScreenPixWidth, currentScreenBPP;
HDC dc;
LONG status;
DWORD* extHdr;
WORD drvExtraSaved;
DEVMODE* deviceMode;
DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE;
TCHAR rMsg[64];
BOOL rturn;
if(!unload)
{
/*
Will have to come back to this for supporting non primary displays and
multimonitor setups
*/
dc = GetDC(NULL);
currentScreenPixHeight = GetDeviceCaps(dc, VERTRES);
currentScreenPixWidth = GetDeviceCaps(dc, HORZRES);
currentScreenBPP = GetDeviceCaps(dc, BITSPIXEL);
ReleaseDC(NULL, dc);
context->height = currentScreenPixHeight;
context->width = currentScreenPixWidth;
context->bitsPerPix = currentScreenBPP;
_tprintf(_T("Detected current screen settings: %dx%dx%d\n"), currentScreenPixHeight, currentScreenPixWidth, currentScreenBPP);
}
else
{
currentScreenPixHeight = 0;
currentScreenPixWidth = 0;
currentScreenBPP = 0;
}
deviceMode = (DEVMODE*) malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
deviceMode->dmDriverExtra = 2 * sizeof(DWORD);
extHdr = (DWORD*)((BYTE*) &deviceMode + sizeof(DEVMODE));
extHdr[0] = dmf_devmodewext_magic_sig;
extHdr[1] = 0;
drvExtraSaved = deviceMode->dmDriverExtra;
memset(deviceMode, 0, sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX);
deviceMode->dmSize = sizeof(DEVMODE);
deviceMode->dmDriverExtra = drvExtraSaved;
deviceMode->dmPelsWidth = currentScreenPixWidth;
deviceMode->dmPelsHeight = currentScreenPixHeight;
deviceMode->dmBitsPerPel = currentScreenBPP;
deviceMode->dmPosition.x = 0;
deviceMode->dmPosition.y = 0;
deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
_tcsncpy_s(deviceMode->dmDeviceName, 32, context->deviceName, _tcslen(context->deviceName));
status = ChangeDisplaySettingsEx(context->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL);
rturn = false;
switch (status)
{
case DISP_CHANGE_SUCCESSFUL:
_tprintf(_T("ChangeDisplaySettingsEx() was successfull\n"));
rturn = true;
break;
case DISP_CHANGE_BADDUALVIEW:
_tcscpy(rMsg, _T("DISP_CHANGE_BADDUALVIEW"));
break;
case DISP_CHANGE_BADFLAGS:
_tcscpy(rMsg, _T("DISP_CHANGE_BADFLAGS"));
break;
case DISP_CHANGE_BADMODE:
_tcscpy(rMsg, _T("DISP_CHANGE_BADMODE"));
break;
case DISP_CHANGE_BADPARAM:
_tcscpy(rMsg, _T("DISP_CHANGE_BADPARAM"));
break;
case DISP_CHANGE_FAILED:
_tcscpy(rMsg, _T("DISP_CHANGE_FAILED"));
break;
case DISP_CHANGE_NOTUPDATED:
_tcscpy(rMsg, _T("DISP_CHANGE_NOTUPDATED"));
break;
case DISP_CHANGE_RESTART:
_tcscpy(rMsg, _T("DISP_CHANGE_RESTART"));
break;
}
if(!rturn)
_tprintf(_T("ChangeDisplaySettingsEx() failed with %s, code %d\n"), rMsg, status);
return rturn;
}
BOOL wf_map_mirror_mem(wfInfo* context)
{
int status;
GETCHANGESBUF* b;
_tprintf(_T("\n\nCreating a device context...\n"));
context->driverDC = CreateDC(context->deviceName, NULL, NULL, NULL);
if (context->driverDC == NULL)
{
_tprintf(_T("Could not create device driver context!\n"));
return false;
}
context->changeBuffer = malloc(sizeof(GETCHANGESBUF));
memset(context->changeBuffer, 0, sizeof(GETCHANGESBUF));
_tprintf(_T("\n\nConnecting to driver...\n"));
status = ExtEscape(context->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), (LPSTR) context->changeBuffer);
if (status <= 0)
{
_tprintf(_T("Failed to map shared memory from the driver! Code %d\n"), status);
}
b = (GETCHANGESBUF*)context->changeBuffer;
_tprintf(_T("ExtEscape() returned code %d\n"), status);
return true;
}
/*
Unmap the shared memory and release the DC
*/
BOOL wf_mirror_cleanup(wfInfo* context)
{
int iResult;
_tprintf(_T("\n\nCleaning up...\nDisconnecting driver...\n"));
iResult = ExtEscape(context->driverDC, dmf_esc_usm_pipe_unmap, sizeof(context->changeBuffer), (LPSTR) context->changeBuffer, 0, 0);
if(iResult <= 0)
{
_tprintf(_T("Failed to unmap shared memory from the driver! Code %d\n"), iResult);
}
_tprintf(_T("Releasing DC\n"));
if(context->driverDC != NULL)
{
iResult = DeleteDC(context->driverDC);
if(iResult == 0)
{
_tprintf(_T("Failed to release DC!\n"));
}
}
free(context->changeBuffer);
return true;
}

209
server/Windows/wf_mirage.h Normal file
View File

@ -0,0 +1,209 @@
/**
* FreeRDP: A Remote Desktop Protocol Client
* FreeRDP Windows Server
*
* 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.
*/
#ifndef WF_MIRAGE_H
#define WF_MIRAGE_H
#include "wfreerdp.h"
enum
{
DMF_ESCAPE_BASE_1_VB = 1030,
DMF_ESCAPE_BASE_2_VB = 1026,
DMF_ESCAPE_BASE_3_VB = 24
};
#ifdef _WIN64
#define CLIENT_64BIT 0x8000
enum
{
DMF_ESCAPE_BASE_1 = CLIENT_64BIT | DMF_ESCAPE_BASE_1_VB,
DMF_ESCAPE_BASE_2 = CLIENT_64BIT | DMF_ESCAPE_BASE_2_VB,
DMF_ESCAPE_BASE_3 = CLIENT_64BIT | DMF_ESCAPE_BASE_3_VB,
};
#else
enum
{
DMF_ESCAPE_BASE_1 = DMF_ESCAPE_BASE_1_VB,
DMF_ESCAPE_BASE_2 = DMF_ESCAPE_BASE_2_VB,
DMF_ESCAPE_BASE_3 = DMF_ESCAPE_BASE_3_VB,
};
#endif
typedef enum
{
dmf_esc_qry_ver_info = DMF_ESCAPE_BASE_2 + 0,
dmf_esc_usm_pipe_map = DMF_ESCAPE_BASE_1 + 0,
dmf_esc_usm_pipe_unmap = DMF_ESCAPE_BASE_1 + 1,
dmf_esc_test = DMF_ESCAPE_BASE_1 + 20,
dmf_esc_usm_pipe_mapping_test = DMF_ESCAPE_BASE_1 + 21,
dmf_esc_pointer_shape_get = DMF_ESCAPE_BASE_3,
} dmf_escape;
#define CLIP_LIMIT 50
#define MAXCHANGES_BUF 20000
typedef enum
{
dmf_dfo_IGNORE = 0,
dmf_dfo_FROM_SCREEN = 1,
dmf_dfo_FROM_DIB = 2,
dmf_dfo_TO_SCREEN = 3,
dmf_dfo_SCREEN_SCREEN = 11,
dmf_dfo_BLIT = 12,
dmf_dfo_SOLIDFILL = 13,
dmf_dfo_BLEND = 14,
dmf_dfo_TRANS = 15,
dmf_dfo_PLG = 17,
dmf_dfo_TEXTOUT = 18,
dmf_dfo_Ptr_Shape = 19,
dmf_dfo_Ptr_Engage = 48,
dmf_dfo_Ptr_Avert = 49,
dmf_dfn_assert_on = 64,
dmf_dfn_assert_off = 65,
} dmf_UpdEvent;
#define NOCACHE 1
#define OLDCACHE 2
#define NEWCACHE 3
typedef struct
{
ULONG type;
RECT rect;
#ifndef DFMIRAGE_LEAN
RECT origrect;
POINT point;
ULONG color;
ULONG refcolor;
#endif
} CHANGES_RECORD;
typedef CHANGES_RECORD* PCHANGES_RECORD;
typedef struct
{
ULONG counter;
CHANGES_RECORD pointrect[MAXCHANGES_BUF];
} CHANGES_BUF;
#define EXT_DEVMODE_SIZE_MAX 3072
#define DMF_PIPE_SEC_SIZE_DEFAULT ALIGN64K(sizeof(CHANGES_BUF))
typedef struct
{
CHANGES_BUF* buffer;
PVOID Userbuffer;
} GETCHANGESBUF;
#define dmf_sprb_ERRORMASK 0x07FF
#define dmf_sprb_STRICTSESSION_AFF 0x1FFF
typedef enum
{
dmf_sprb_internal_error = 0x0001,
dmf_sprb_miniport_gen_error = 0x0004,
dmf_sprb_memory_alloc_failed = 0x0008,
dmf_sprb_pipe_buff_overflow = 0x0010,
dmf_sprb_pipe_buff_insufficient = 0x0020,
dmf_sprb_pipe_not_ready = 0x0040,
dmf_sprb_gdi_err = 0x0100,
dmf_sprb_owner_died = 0x0400,
dmf_sprb_tgtwnd_gone = 0x0800,
dmf_sprb_pdev_detached = 0x2000,
} dmf_session_prob_status;
#define DMF_ESC_RET_FAILF 0x80000000
#define DMF_ESC_RET_SSTMASK 0x0000FFFF
#define DMF_ESC_RET_IMMMASK 0x7FFF0000
typedef enum
{
dmf_escret_generic_ok = 0x00010000,
dmf_escret_bad_state = 0x00100000,
dmf_escret_access_denied = 0x00200000,
dmf_escret_bad_buffer_size = 0x00400000,
dmf_escret_internal_err = 0x00800000,
dmf_escret_out_of_memory = 0x02000000,
dmf_escret_already_connected = 0x04000000,
dmf_escret_oh_boy_too_late = 0x08000000,
dmf_escret_bad_window = 0x10000000,
dmf_escret_drv_ver_higher = 0x20000000,
dmf_escret_drv_ver_lower = 0x40000000,
} dmf_esc_retcode;
typedef struct
{
ULONG cbSize;
ULONG app_actual_version;
ULONG display_minreq_version;
ULONG connect_options;
} Esc_dmf_Qvi_IN;
enum
{
esc_qvi_prod_name_max = 16,
};
#define ESC_QVI_PROD_MIRAGE "MIRAGE"
#define ESC_QVI_PROD_QUASAR "QUASAR"
typedef struct
{
ULONG cbSize;
ULONG display_actual_version;
ULONG miniport_actual_version;
ULONG app_minreq_version;
ULONG display_buildno;
ULONG miniport_buildno;
char prod_name[esc_qvi_prod_name_max];
} Esc_dmf_Qvi_OUT;
typedef struct
{
ULONG cbSize;
char* pDstBmBuf;
ULONG nDstBmBufSize;
} Esc_dmf_pointer_shape_get_IN;
typedef struct
{
ULONG cbSize;
POINTL BmSize;
char* pMaskBm;
ULONG nMaskBmSize;
char* pColorBm;
ULONG nColorBmSize;
char* pColorBmPal;
ULONG nColorBmPalEntries;
} Esc_dmf_pointer_shape_get_OUT;
BOOL wf_check_disp_devices(wfInfo* context);
BOOL wf_disp_device_set_attatch(wfInfo* context, DWORD val);
BOOL wf_update_mirror_drv(wfInfo* context, int unload);
BOOL wf_map_mirror_mem(wfInfo* context);
BOOL wf_mirror_cleanup(wfInfo* context);
#endif /* WF_MIRAGE_H */

View File

@ -21,21 +21,160 @@
#include "config.h"
#endif
#include <winpr/tchar.h>
#include <winpr/windows.h>
#include <freerdp/listener.h>
#include <freerdp/utils/sleep.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/utils/stream.h>
#include "wf_mirage.h"
#include "wf_peer.h"
void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context)
{
wfInfoSingleton = wf_info_init(wfInfoSingleton);
wf_info_mirror_init(wfInfoSingleton, context);
}
void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context)
{
if (context)
wf_info_subscriber_release(wfInfoSingleton, context);
}
static DWORD WINAPI wf_peer_mirror_monitor(LPVOID lpParam)
{
DWORD start, end, diff;
DWORD rate;
freerdp_peer* client;
rate = 42;
client = (freerdp_peer*)lpParam;
//todo: make sure we dont encode after no clients
while(1)
{
start = GetTickCount();
if(wf_info_has_subscribers(wfInfoSingleton))
{
wf_info_update_changes(wfInfoSingleton);
if(wf_info_have_updates(wfInfoSingleton))
{
//wf_info_find_invalid_region(wfInfoSingleton);
//printf("Fake Encode!\n");
wf_rfx_encode(client);
}
}
end = GetTickCount();
diff = end - start;
if(diff < rate)
{
//printf("sleeping for %d ms...\n", rate - diff);
Sleep(rate - diff);
}
}
_tprintf(_T("monitor thread terminating...\n"));
wf_info_set_thread_count(wfInfoSingleton, wf_info_get_thread_count(wfInfoSingleton) - 1 );
return 0;
}
void wf_rfx_encode(freerdp_peer* client)
{
STREAM* s;
wfInfo* wfi;
RFX_RECT rect;
rdpUpdate* update;
wfPeerContext* wfp;
SURFACE_BITS_COMMAND* cmd;
GETCHANGESBUF* buf;
long height, width;
long offset;
int dRes;
wfp = (wfPeerContext*) client->context;
dRes = WaitForSingleObject(wfInfoSingleton->encodeMutex, INFINITE);
switch(dRes)
{
case WAIT_OBJECT_0:
wf_info_find_invalid_region(wfInfoSingleton);
if( (wfp->activated == false) ||
(wf_info_has_subscribers(wfInfoSingleton) == false) ||
!wf_info_have_invalid_region(wfInfoSingleton) ||
(wfInfoSingleton->enc_data == true) )
{
ReleaseMutex(wfInfoSingleton->encodeMutex);
break;
}
update = client->update;
cmd = &update->surface_bits_command;
wfi = wfp->wfInfo;
buf = (GETCHANGESBUF*)wfi->changeBuffer;
//printf("encode %d\n", wfi->nextUpdate - wfi->lastUpdate);
//printf("\tinvlaid region = (%d, %d), (%d, %d)\n", wfi->invalid_x1, wfi->invalid_y1, wfi->invalid_x2, wfi->invalid_y2);
width = wfi->invalid_x2 - wfi->invalid_x1;
height = wfi->invalid_y2 - wfi->invalid_y1;
stream_clear(wfp->s);
stream_set_pos(wfp->s, 0);
s = wfp->s;
rect.x = 0;
rect.y = 0;
rect.width = (uint16) width;
rect.height = (uint16) height;
offset = (4 * wfi->invalid_x1) + (wfi->invalid_y1 * wfi->width * 4);
//printf("width = %d, height = %d\n", width, height);
rfx_compose_message(wfp->rfx_context, s, &rect, 1,
((uint8*) (buf->Userbuffer)) + offset, width, height, wfi->width * 4);
cmd->destLeft = wfi->invalid_x1;
cmd->destTop = wfi->invalid_y1;
cmd->destRight = wfi->invalid_x1 + width;
cmd->destBottom = wfi->invalid_y1 + height;
cmd->bpp = 32;
cmd->codecID = client->settings->rfx_codec_id;
cmd->width = width;
cmd->height = height;
cmd->bitmapDataLength = stream_get_length(s);
cmd->bitmapData = stream_get_head(s);
wfi->enc_data = true;
ReleaseMutex(wfInfoSingleton->encodeMutex);
break;
case WAIT_TIMEOUT:
ReleaseMutex(wfInfoSingleton->encodeMutex);
break;
case WAIT_ABANDONED:
printf("\n\nwf_rfx_encode: Got ownership of abandoned mutex... releasing...\n", dRes);
ReleaseMutex(wfInfoSingleton->encodeMutex);
break;
default:
printf("\n\nwf_rfx_encode: Something else happened!!! dRes = %d\n", dRes);
}
}
void wf_peer_init(freerdp_peer* client)
@ -44,6 +183,16 @@ void wf_peer_init(freerdp_peer* client)
client->ContextNew = (psPeerContextNew) wf_peer_context_new;
client->ContextFree = (psPeerContextFree) wf_peer_context_free;
freerdp_peer_context_new(client);
if (!wf_info_get_thread_count(wfInfoSingleton))
{
_tprintf(_T("Trying to create a monitor thread...\n"));
if (CreateThread(NULL, 0, wf_peer_mirror_monitor, client, 0, NULL) != 0)
_tprintf(_T("Created!\n"));
wf_info_set_thread_count(wfInfoSingleton, wf_info_get_thread_count(wfInfoSingleton) + 1 );
}
}
boolean wf_peer_post_connect(freerdp_peer* client)
@ -73,6 +222,16 @@ boolean wf_peer_post_connect(freerdp_peer* client)
printf("Client requested desktop: %dx%dx%d\n",
client->settings->width, client->settings->height, client->settings->color_depth);
printf("But we will try resizing to %dx%d\n",
wf_info_get_width(wfInfoSingleton),
wf_info_get_height(wfInfoSingleton)
);
client->settings->width = wf_info_get_width(wfInfoSingleton);
client->settings->height = wf_info_get_height(wfInfoSingleton);
client->update->DesktopResize(client->update->context);
return true;
}
@ -89,3 +248,45 @@ void wf_peer_synchronize_event(rdpInput* input, uint32 flags)
{
}
void wf_peer_send_changes(rdpUpdate* update)
{
int dRes;
//are we currently encoding?
dRes = WaitForSingleObject(wfInfoSingleton->encodeMutex, 0);
switch(dRes)
{
case WAIT_OBJECT_0:
//are there changes to send?
if( !wf_info_have_updates(wfInfoSingleton) || !wf_info_have_invalid_region(wfInfoSingleton) || (wfInfoSingleton->enc_data == false) )
{
ReleaseMutex(wfInfoSingleton->encodeMutex);
break;
}
wf_info_updated(wfInfoSingleton);
/*
printf("\tSend...");
printf("\t(%d, %d), (%d, %d) [%dx%d]\n",
update->surface_bits_command.destLeft, update->surface_bits_command.destTop,
update->surface_bits_command.destRight, update->surface_bits_command.destBottom,
update->surface_bits_command.width, update->surface_bits_command.height);
*/
update->SurfaceBits(update->context, &update->surface_bits_command);
//wf_info_clear_invalid_region(wfInfoSingleton);
wfInfoSingleton->enc_data = false;
ReleaseMutex(wfInfoSingleton->encodeMutex);
break;
case WAIT_TIMEOUT:
break;
default:
printf("wf_peer_send_changes: Something else happened!!! dRes = %d\n", dRes);
}
}

View File

@ -21,15 +21,23 @@
#define WF_PEER_H
#include "wfreerdp.h"
#include "wf_info.h"
void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context);
void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context);
void wf_peer_init(freerdp_peer* client);
void wf_rfx_encode(freerdp_peer* client);
//void wf_peer_rfx_update(freerdp_peer* client, int x, int y, int width, int height);
boolean wf_peer_post_connect(freerdp_peer* client);
boolean wf_peer_activate(freerdp_peer* client);
void wf_peer_synchronize_event(rdpInput* input, uint32 flags);
void wf_peer_send_changes(rdpUpdate* update);
wfInfo * wfInfoSingleton;
#endif /* WF_PEER_H */

View File

@ -44,6 +44,8 @@
HANDLE g_done_event;
int g_thread_count = 0;
BOOL derp = false;
static DWORD WINAPI wf_peer_main_loop(LPVOID lpParam)
{
int rcount;
@ -88,6 +90,9 @@ static DWORD WINAPI wf_peer_main_loop(LPVOID lpParam)
printf("Failed to check FreeRDP file descriptor\n");
break;
}
if(client->activated)
wf_peer_send_changes(client->update);
}
printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname);
@ -129,6 +134,7 @@ static void wf_server_main_loop(freerdp_listener* instance)
printf("Failed to check FreeRDP file descriptor\n");
break;
}
Sleep(20);
}
instance->Close(instance);
@ -188,4 +194,3 @@ int main(int argc, char* argv[])
return 0;
}

View File

@ -21,12 +21,21 @@
#define WFREERDP_H
#include <freerdp/freerdp.h>
#include <freerdp/codec/rfx.h>
#include "wf_info.h"
struct wf_peer_context
{
rdpContext _p;
wfInfo* wfInfo;
boolean activated;
RFX_CONTEXT* rfx_context;
STREAM* s;
};
typedef struct wf_peer_context wfPeerContext;
extern wfInfo * wfInfoSingleton;
#endif /* WFREERDP_H */