From 343983d9af97637421763b46ce1ccd5258a60693 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 26 Jul 2018 03:08:52 +1000 Subject: [PATCH] [host] add timeout return value for repeated frame This is to allow a repeat frame without incuring an additional memory copy when the frame is already in shared memory. --- host/ICapture.h | 1 + host/Service.cpp | 95 ++++++++++++++++++++++++++++-------------------- host/Service.h | 7 +++- 3 files changed, 61 insertions(+), 42 deletions(-) diff --git a/host/ICapture.h b/host/ICapture.h index 97813135..0aa0ed29 100644 --- a/host/ICapture.h +++ b/host/ICapture.h @@ -52,6 +52,7 @@ struct FrameInfo enum GrabStatus { GRAB_STATUS_OK, + GRAB_STATUS_TIMEOUT, GRAB_STATUS_REINIT, GRAB_STATUS_CURSOR, GRAB_STATUS_ERROR diff --git a/host/Service.cpp b/host/Service.cpp index 0c9098ad..d2830713 100644 --- a/host/Service.cpp +++ b/host/Service.cpp @@ -87,13 +87,6 @@ bool Service::Initialize(ICapture * captureDevice) return false; } - m_timer = CreateWaitableTimer(NULL, TRUE, NULL); - if (!m_timer) - { - DEBUG_ERROR("Failed to create waitable timer"); - return false; - } - // Create the cursor thread m_cursorThread = CreateThread(NULL, 0, _CursorThread, this, 0, NULL); m_cursorEvent = CreateEvent (NULL, FALSE, FALSE, L"CursorEvent"); @@ -108,6 +101,7 @@ bool Service::Initialize(ICapture * captureDevice) ZeroMemory(&m_shmHeader->cursor, sizeof(KVMFRCursor)); m_shmHeader->flags &= ~KVMFR_HEADER_FLAG_RESTART; + m_haveFrame = false; m_initialized = true; return true; } @@ -120,47 +114,45 @@ bool Service::InitPointers() m_shmHeader = reinterpret_cast(m_memory); m_cursorData = (uint8_t *)ALIGN_UP(m_memory + sizeof(KVMFRHeader)); m_cursorDataSize = 1048576; // 1MB fixed for cursor size, should be more then enough - m_frame[0] = (uint8_t *)ALIGN_UP(m_cursorData + m_cursorDataSize); - m_frameSize = ALIGN_DN((m_ivshmem->GetSize() - (m_frame[0] - m_memory)) >> 1); - m_frame[1] = (uint8_t *)ALIGN_DN(m_frame[0] + m_frameSize); + m_cursorOffset = m_cursorData - m_memory; - - m_cursorOffset = m_cursorData - m_memory; - m_dataOffset[0] = m_frame[0] - m_memory; - m_dataOffset[1] = m_frame[1] - m_memory; + uint8_t * m_frames = (uint8_t *)ALIGN_UP(m_cursorData + m_cursorDataSize); + m_frameSize = ALIGN_DN((m_ivshmem->GetSize() - (m_frames - m_memory)) / MAX_FRAMES); DEBUG_INFO("Total Available : %3u MB", (unsigned int)(m_ivshmem->GetSize() / 1024 / 1024)); DEBUG_INFO("Max Cursor Size : %3u MB", (unsigned int)(m_cursorDataSize / 1024 / 1024)); DEBUG_INFO("Max Frame Size : %3u MB", (unsigned int)(m_frameSize / 1024 / 1024)); - DEBUG_INFO("Cursor : %p (0x%08x)", m_cursorData, (int)m_cursorOffset ); - DEBUG_INFO("Frame 1 : %p (0x%08x)", m_frame[0] , (int)m_dataOffset[0]); - DEBUG_INFO("Frame 2 : %p (0x%08x)", m_frame[1] , (int)m_dataOffset[1]); + DEBUG_INFO("Cursor : %p (0x%08x)", m_cursorData, (int)m_cursorOffset); + + for (int i = 0; i < MAX_FRAMES; ++i) + { + m_frame[i] = m_frames + i * m_frameSize; + m_dataOffset[i] = m_frame[i] - m_memory; + DEBUG_INFO("Frame %d : %p (0x%08x)", i, m_frame[i], (int)m_dataOffset[i]); + } return true; } void Service::DeInitialize() { - if (m_timer) - { - CloseHandle(m_timer); - m_timer = NULL; - } - - m_shmHeader = NULL; - m_cursorData = NULL; - m_frame[0] = NULL; - m_frame[1] = NULL; - m_cursorOffset = 0; - m_dataOffset[0] = 0; - m_dataOffset[1] = 0; - m_cursorDataSize = 0; - m_frameSize = 0; - WaitForSingleObject(m_cursorThread, INFINITE); CloseHandle(m_cursorThread); CloseHandle(m_cursorEvent); + m_shmHeader = NULL; + m_cursorData = NULL; + m_cursorDataSize = 0; + m_cursorOffset = 0; + m_haveFrame = false; + + for(int i = 0; i < MAX_FRAMES; ++i) + { + m_frame [i] = NULL; + m_dataOffset[i] = 0; + } + m_frameSize = 0; + m_ivshmem->DeInitialize(); if (m_capture) @@ -218,6 +210,7 @@ bool Service::Process() bool ok = false; bool cursorOnly = false; + bool repeat = false; for(int i = 0; i < 2; ++i) { // capture a frame of data @@ -227,6 +220,20 @@ bool Service::Process() ok = true; break; + case GRAB_STATUS_TIMEOUT: + if (m_haveFrame) + { + ok = true; + repeat = true; + if (--m_frameIndex < 0) + m_frameIndex = MAX_FRAMES - 1; + break; + } + + // capture timeouts are not errors + --i; + continue; + case GRAB_STATUS_CURSOR: ok = true; cursorOnly = true; @@ -309,15 +316,23 @@ bool Service::Process() { KVMFRFrame * fi = &m_shmHeader->frame; - fi->type = m_capture->GetFrameType(); - fi->width = frame.width; - fi->height = frame.height; - fi->stride = frame.stride; - fi->pitch = frame.pitch; - fi->dataPos = m_dataOffset[m_frameIndex]; - if (++m_frameIndex == 2) + // only update the header if the frame is new + if (!repeat) + { + fi->type = m_capture->GetFrameType(); + fi->width = frame.width; + fi->height = frame.height; + fi->stride = frame.stride; + fi->pitch = frame.pitch; + fi->dataPos = m_dataOffset[m_frameIndex]; + } + + if (++m_frameIndex == MAX_FRAMES) m_frameIndex = 0; + // remember that we have a valid frame + m_haveFrame = true; + // signal a frame update fi->flags |= KVMFR_FRAME_FLAG_UPDATE; } diff --git a/host/Service.h b/host/Service.h index 39726eff..9fc85585 100644 --- a/host/Service.h +++ b/host/Service.h @@ -26,6 +26,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "IVSHMEM.h" #include "ICapture.h" +#define MAX_FRAMES 2 + class Service { public: @@ -57,9 +59,10 @@ private: KVMFRHeader * m_shmHeader; - uint8_t * m_frame[2]; + bool m_haveFrame; + uint8_t * m_frame[MAX_FRAMES]; size_t m_frameSize; - uint64_t m_dataOffset[2]; + uint64_t m_dataOffset[MAX_FRAMES]; int m_frameIndex; static DWORD WINAPI _CursorThread(LPVOID lpParameter) { return ((Service *)lpParameter)->CursorThread(); }