/** * FreeRDP: A Remote Desktop Protocol Client * FreeRDP Windows Server * * Copyright 2012 Marc-Andre Moreau * Copyright 2012 Corey Clayton * * 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 #include #include #include #include #include "wf_peer.h" #include "wf_info.h" #include "wf_mirage.h" #include "wf_update.h" #include #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); } }