diff options
Diffstat (limited to 'server/Windows/wf_update.c')
-rw-r--r-- | server/Windows/wf_update.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/server/Windows/wf_update.c b/server/Windows/wf_update.c new file mode 100644 index 0000000..06d60c9 --- /dev/null +++ b/server/Windows/wf_update.c @@ -0,0 +1,251 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Windows Server + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * 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 <freerdp/config.h> + +#include <stdio.h> + +#include <winpr/windows.h> + +#include <freerdp/freerdp.h> +#include <freerdp/listener.h> + +#include "wf_peer.h" +#include "wf_info.h" +#include "wf_mirage.h" + +#include "wf_update.h" + +#include <freerdp/log.h> +#define TAG SERVER_TAG("windows") + +DWORD WINAPI wf_update_thread(LPVOID lpParam) +{ + DWORD fps; + wfInfo* wfi; + DWORD beg, end; + DWORD diff, rate; + wfi = (wfInfo*)lpParam; + fps = wfi->framesPerSecond; + rate = 1000 / fps; + + while (1) + { + beg = GetTickCount(); + + if (wf_info_lock(wfi) > 0) + { + if (wfi->activePeerCount > 0) + { + wf_info_update_changes(wfi); + + if (wf_info_have_updates(wfi)) + { + wf_update_encode(wfi); + // WLog_DBG(TAG, "Start of parallel sending"); + int index = 0; + + for (int peerindex = 0; peerindex < wfi->peerCount; peerindex++) + { + for (; index < FREERDP_SERVER_WIN_INFO_MAXPEERS; index++) + { + if (wfi->peers[index] && wfi->peers[index]->activated) + { + // WLog_DBG(TAG, "Setting event for %d of %d", index + 1, + // wfi->activePeerCount); + SetEvent(((wfPeerContext*)wfi->peers[index]->context)->updateEvent); + } + } + } + + for (int index = 0; index < wfi->activePeerCount; index++) + { + // WLog_DBG(TAG, "Waiting for %d of %d", index + 1, wfi->activePeerCount); + // WaitForSingleObject(wfi->updateSemaphore, INFINITE); + WaitForSingleObject(wfi->updateSemaphore, 1000); + } + + // WLog_DBG(TAG, "End of parallel sending"); + wf_info_clear_invalid_region(wfi); + } + } + + wf_info_unlock(wfi); + } + + end = GetTickCount(); + diff = end - beg; + + if (diff < rate) + { + Sleep(rate - diff); + } + } + + // WLog_DBG(TAG, "Exiting Update Thread"); + return 0; +} + +void wf_update_encode(wfInfo* wfi) +{ + RFX_RECT rect; + long height, width; + BYTE* pDataBits = NULL; + int stride; + SURFACE_BITS_COMMAND* cmd; + wf_info_find_invalid_region(wfi); + cmd = &wfi->cmd; + Stream_SetPosition(wfi->s, 0); + wf_info_getScreenData(wfi, &width, &height, &pDataBits, &stride); + rect.x = 0; + rect.y = 0; + rect.width = (UINT16)width; + rect.height = (UINT16)height; + // WLog_DBG(TAG, "x:%"PRId32" y:%"PRId32" w:%ld h:%ld", wfi->invalid.left, wfi->invalid.top, + // width, height); + Stream_Clear(wfi->s); + + if (!(rfx_compose_message(wfi->rfx_context, wfi->s, &rect, 1, pDataBits, width, height, + stride))) + { + return; + } + + wfi->frame_idx = rfx_context_get_frame_idx(wfi->rfx_context); + cmd->destLeft = wfi->invalid.left; + cmd->destTop = wfi->invalid.top; + cmd->destRight = wfi->invalid.left + width; + cmd->destBottom = wfi->invalid.top + height; + cmd->bmp.bpp = 32; + cmd->bmp.codecID = 3; + cmd->bmp.width = width; + cmd->bmp.height = height; + cmd->bmp.bitmapDataLength = Stream_GetPosition(wfi->s); + cmd->bmp.bitmapData = Stream_Buffer(wfi->s); +} + +void wf_update_peer_send(wfInfo* wfi, wfPeerContext* context) +{ + freerdp_peer* client; + + WINPR_ASSERT(wfi); + WINPR_ASSERT(context); + + client = ((rdpContext*)context)->peer; + WINPR_ASSERT(client); + + /* This happens when the RemoteFX encoder state is reset */ + + if (wfi->frame_idx == 1) + context->frame_idx = 0; + + /* + * When a new client connects, it is possible that old frames from + * from a previous encoding state remain. Those frames should be discarded + * as they will cause an error condition in mstsc. + */ + + if ((context->frame_idx + 1) != wfi->frame_idx) + { + /* This frame is meant to be discarded */ + if (context->frame_idx == 0) + return; + + /* This is an unexpected error condition */ + WLog_DBG(TAG, "Unexpected Frame Index: Actual: %d Expected: %d", wfi->frame_idx, + context->frame_idx + 1); + } + + WINPR_ASSERT(client->context); + WINPR_ASSERT(client->context->settings); + WINPR_ASSERT(client->context->update); + WINPR_ASSERT(client->context->update->SurfaceBits); + + wfi->cmd.bmp.codecID = + freerdp_settings_get_uint32(client->context->settings, FreeRDP_RemoteFxCodecId); + client->context->update->SurfaceBits(client->context, &wfi->cmd); + context->frame_idx++; +} + +void wf_update_encoder_reset(wfInfo* wfi) +{ + if (wf_info_lock(wfi) > 0) + { + WLog_DBG(TAG, "Resetting encoder"); + + if (wfi->rfx_context) + { + rfx_context_reset(wfi->rfx_context, wfi->servscreen_width, wfi->servscreen_height); + } + else + { + /* TODO: pass ThreadingFlags somehow */ + wfi->rfx_context = rfx_context_new(TRUE); + rfx_context_set_mode(wfi->rfx_context, RLGR3); + rfx_context_reset(wfi->rfx_context, wfi->servscreen_width, wfi->servscreen_height); + rfx_context_set_pixel_format(wfi->rfx_context, PIXEL_FORMAT_BGRA32); + wfi->s = Stream_New(NULL, 0xFFFF); + } + + wf_info_invalidate_full_screen(wfi); + wf_info_unlock(wfi); + } +} + +void wf_update_peer_activate(wfInfo* wfi, wfPeerContext* context) +{ + if (wf_info_lock(wfi) > 0) + { + if (wfi->activePeerCount < 1) + { +#ifndef WITH_DXGI_1_2 + wf_mirror_driver_activate(wfi); +#endif + ResumeThread(wfi->updateThread); + } + + wf_update_encoder_reset(wfi); + wfi->activePeerCount++; + WLog_DBG(TAG, "Activating Peer Updates: %d", wfi->activePeerCount); + wf_info_unlock(wfi); + } +} + +void wf_update_peer_deactivate(wfInfo* wfi, wfPeerContext* context) +{ + if (wf_info_lock(wfi) > 0) + { + freerdp_peer* client = ((rdpContext*)context)->peer; + + if (client->activated) + { + if (wfi->activePeerCount <= 1) + { + wf_mirror_driver_deactivate(wfi); + } + + client->activated = FALSE; + wfi->activePeerCount--; + WLog_DBG(TAG, "Deactivating Peer Updates: %d", wfi->activePeerCount); + } + + wf_info_unlock(wfi); + } +} |