diff --git a/host/Capture/DXGI.cpp b/host/Capture/DXGI.cpp index 40142070..9f03113c 100644 --- a/host/Capture/DXGI.cpp +++ b/host/Capture/DXGI.cpp @@ -348,12 +348,15 @@ size_t DXGI::GetMaxFrameSize() return (m_width * m_height * 4); } -GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct CursorInfo & cursor, ID3D11Texture2DPtr & texture, bool & timeout) +GrabStatus Capture::DXGI::Capture() { if (!m_initialized) return GRAB_STATUS_ERROR; - timeout = false; + m_cursor.updated = false; + m_cursor.hasPos = false; + m_cursor.hasShape = false; + DXGI_OUTDUPL_FRAME_INFO frameInfo; IDXGIResourcePtr res; @@ -368,10 +371,7 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs status = m_dup->AcquireNextFrame(1000, &frameInfo, &res); if (status == DXGI_ERROR_WAIT_TIMEOUT) - { - timeout = true; - return GRAB_STATUS_OK; - } + return GRAB_STATUS_TIMEOUT; if (FAILED(status)) break; @@ -385,27 +385,27 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs m_lastMousePos.x != frameInfo.PointerPosition.Position.x || m_lastMousePos.y != frameInfo.PointerPosition.Position.y ) { - cursor.updated = true; - cursor.hasPos = true; - cursor.x = frameInfo.PointerPosition.Position.x; - cursor.y = frameInfo.PointerPosition.Position.y; + m_cursor.updated = true; + m_cursor.hasPos = true; + m_cursor.x = frameInfo.PointerPosition.Position.x; + m_cursor.y = frameInfo.PointerPosition.Position.y; m_lastMousePos.x = frameInfo.PointerPosition.Position.x; m_lastMousePos.y = frameInfo.PointerPosition.Position.y; } if (m_lastMouseVis != frameInfo.PointerPosition.Visible) { - cursor.updated = true; + m_cursor.updated = true; m_lastMouseVis = frameInfo.PointerPosition.Visible; } - cursor.visible = m_lastMouseVis == TRUE; + m_cursor.visible = m_lastMouseVis == TRUE; } // if the pointer shape has changed if (frameInfo.PointerShapeBufferSize > 0) { - cursor.updated = true; + m_cursor.updated = true; if (m_pointerBufSize < frameInfo.PointerShapeBufferSize) { if (m_pointer) @@ -424,20 +424,20 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs switch (shapeInfo.Type) { - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : cursor.type = CURSOR_TYPE_COLOR; break; - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: cursor.type = CURSOR_TYPE_MASKED_COLOR; break; - case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : cursor.type = CURSOR_TYPE_MONOCHROME; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : m_cursor.type = CURSOR_TYPE_COLOR; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: m_cursor.type = CURSOR_TYPE_MASKED_COLOR; break; + case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : m_cursor.type = CURSOR_TYPE_MONOCHROME; break; default: DEBUG_ERROR("Invalid cursor type"); return GRAB_STATUS_ERROR; } - cursor.hasShape = true; - cursor.shape = m_pointer; - cursor.w = shapeInfo.Width; - cursor.h = shapeInfo.Height; - cursor.pitch = shapeInfo.Pitch; - cursor.dataSize = m_pointerSize; + m_cursor.hasShape = true; + m_cursor.shape = m_pointer; + m_cursor.w = shapeInfo.Width; + m_cursor.h = shapeInfo.Height; + m_cursor.pitch = shapeInfo.Pitch; + m_cursor.dataSize = m_pointerSize; } // if we also have frame data, break out to process it @@ -447,7 +447,7 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs res = NULL; // if the cursor has been updated - if (cursor.updated) + if (m_cursor.updated) return GRAB_STATUS_CURSOR; // otherwise just try again @@ -477,9 +477,9 @@ GrabStatus Capture::DXGI::GrabFrameTexture(struct FrameInfo & frame, struct Curs return GRAB_STATUS_ERROR; } - res.QueryInterface(IID_PPV_ARGS(&texture)); + res.QueryInterface(IID_PPV_ARGS(&m_ftexture)); - if (!texture) + if (!m_ftexture) { ReleaseFrame(); DEBUG_ERROR("Failed to get src ID3D11Texture2D"); @@ -495,6 +495,8 @@ GrabStatus Capture::DXGI::ReleaseFrame() return GRAB_STATUS_OK; m_releaseFrame = false; + m_ftexture = NULL; + switch (m_dup->ReleaseFrame()) { case S_OK: @@ -512,21 +514,17 @@ GrabStatus Capture::DXGI::ReleaseFrame() return GRAB_STATUS_OK; } -GrabStatus Capture::DXGI::GrabFrameRaw(FrameInfo & frame, struct CursorInfo & cursor) +GrabStatus Capture::DXGI::DiscardFrame() +{ + return ReleaseFrame(); +} + +GrabStatus Capture::DXGI::GrabFrameRaw(FrameInfo & frame) { GrabStatus result; - ID3D11Texture2DPtr texture; - bool timeout; D3D11_MAPPED_SUBRESOURCE mapping; - result = GrabFrameTexture(frame, cursor, texture, timeout); - if (timeout) - return GRAB_STATUS_TIMEOUT; - - if (result != GRAB_STATUS_OK) - return result; - - m_deviceContext->CopyResource(m_texture[0], texture); + m_deviceContext->CopyResource(m_texture[0], m_ftexture); result = ReleaseFrame(); if (result != GRAB_STATUS_OK) @@ -556,21 +554,12 @@ GrabStatus Capture::DXGI::GrabFrameRaw(FrameInfo & frame, struct CursorInfo & cu return GRAB_STATUS_OK; } -GrabStatus Capture::DXGI::GrabFrameYUV420(struct FrameInfo & frame, struct CursorInfo & cursor) +GrabStatus Capture::DXGI::GrabFrameYUV420(struct FrameInfo & frame) { GrabStatus result; - ID3D11Texture2DPtr texture; - bool timeout; - - result = GrabFrameTexture(frame, cursor, texture, timeout); - if (timeout) - return GRAB_STATUS_TIMEOUT; - - if (result != GRAB_STATUS_OK) - return result; TextureList planes; - if (!m_textureConverter->Convert(texture, planes)) + if (!m_textureConverter->Convert(m_ftexture, planes)) return GRAB_STATUS_ERROR; for(int i = 0; i < 3; ++i) @@ -624,7 +613,7 @@ GrabStatus Capture::DXGI::GrabFrameYUV420(struct FrameInfo & frame, struct Curso return GRAB_STATUS_OK; } -GrabStatus Capture::DXGI::GrabFrameH264(struct FrameInfo & frame, struct CursorInfo & cursor) +GrabStatus Capture::DXGI::GrabFrameH264(struct FrameInfo & frame) { return GRAB_STATUS_ERROR; #if 0 @@ -673,16 +662,27 @@ GrabStatus Capture::DXGI::GrabFrameH264(struct FrameInfo & frame, struct CursorI #endif } -GrabStatus DXGI::GrabFrame(struct FrameInfo & frame, struct CursorInfo & cursor) +GrabStatus DXGI::GetFrame(struct FrameInfo & frame) { + if (!m_ftexture) + { + DEBUG_ERROR("A frame has not been captured"); + return GRAB_STATUS_ERROR; + } + frame.width = m_width; frame.height = m_height; switch (m_frameType) - { - case FRAME_TYPE_YUV420: return GrabFrameYUV420(frame, cursor); - case FRAME_TYPE_H264 : return GrabFrameH264 (frame, cursor); + { + case FRAME_TYPE_YUV420: return GrabFrameYUV420(frame); + case FRAME_TYPE_H264 : return GrabFrameH264 (frame); } - return GrabFrameRaw(frame, cursor); + return GrabFrameRaw(frame); +} + +const CursorInfo & DXGI::GetCursor() +{ + return m_cursor; } \ No newline at end of file diff --git a/host/Capture/DXGI.h b/host/Capture/DXGI.h index 45471f85..afca14c6 100644 --- a/host/Capture/DXGI.h +++ b/host/Capture/DXGI.h @@ -56,18 +56,23 @@ namespace Capture enum FrameType GetFrameType(); size_t GetMaxFrameSize(); - enum GrabStatus GrabFrame(struct FrameInfo & frame, struct CursorInfo & cursor); + GrabStatus Capture(); + GrabStatus GetFrame (struct FrameInfo & frame ); + const CursorInfo & GetCursor(); + GrabStatus DiscardFrame(); private: bool InitRawCapture(); bool InitYUV420Capture(); bool InitH264Capture(); - GrabStatus GrabFrameTexture(struct FrameInfo & frame, struct CursorInfo & cursor, ID3D11Texture2DPtr & texture, bool & timeout); + struct CursorInfo m_cursor; + ID3D11Texture2DPtr m_ftexture; + GrabStatus ReleaseFrame(); - GrabStatus GrabFrameRaw (struct FrameInfo & frame, struct CursorInfo & cursor); - GrabStatus GrabFrameYUV420 (struct FrameInfo & frame, struct CursorInfo & cursor); - GrabStatus GrabFrameH264 (struct FrameInfo & frame, struct CursorInfo & cursor); + GrabStatus GrabFrameRaw (struct FrameInfo & frame); + GrabStatus GrabFrameYUV420 (struct FrameInfo & frame); + GrabStatus GrabFrameH264 (struct FrameInfo & frame); CaptureOptions * m_options; diff --git a/host/ICapture.h b/host/ICapture.h index 0aa0ed29..0d76b51f 100644 --- a/host/ICapture.h +++ b/host/ICapture.h @@ -71,5 +71,8 @@ public: virtual bool ReInitialize() = 0; virtual enum FrameType GetFrameType() = 0; virtual size_t GetMaxFrameSize() = 0; - virtual enum GrabStatus GrabFrame(struct FrameInfo & frame, struct CursorInfo & cursor) = 0; + virtual enum GrabStatus Capture() = 0; + virtual enum GrabStatus GetFrame(struct FrameInfo & frame) = 0; + virtual const CursorInfo & GetCursor() = 0; + virtual enum GrabStatus DiscardFrame() = 0; }; diff --git a/host/Service.cpp b/host/Service.cpp index 4e9ea4f3..3a9c8332 100644 --- a/host/Service.cpp +++ b/host/Service.cpp @@ -98,8 +98,8 @@ bool Service::Initialize(ICapture * captureDevice) m_shmHeader->version = KVMFR_HEADER_VERSION; // zero and tell the client we have restarted - ZeroMemory(&m_shmHeader->frame , sizeof(KVMFRFrame )); - ZeroMemory(&m_shmHeader->cursor, sizeof(KVMFRCursor)); + ZeroMemory(&(m_shmHeader->frame ), sizeof(KVMFRFrame )); + ZeroMemory(&(m_shmHeader->cursor), sizeof(KVMFRCursor)); m_shmHeader->flags &= ~KVMFR_HEADER_FLAG_RESTART; m_haveFrame = false; @@ -171,54 +171,28 @@ bool Service::Process() if (!m_initialized) return false; - volatile uint8_t *flags = &m_shmHeader->flags; - int tryCount = 0; + volatile uint8_t *flags = &(m_shmHeader->flags); - // wait for the host to notify that is it is ready to proceed - while (true) + // check if the client has flagged a restart + if (*flags & KVMFR_HEADER_FLAG_RESTART) { - // check if the client has flagged a restart - if (*flags & KVMFR_HEADER_FLAG_RESTART) + DEBUG_INFO("Restart Requested"); + if (!m_capture->ReInitialize()) { - DEBUG_INFO("Restart Requested"); - if (!m_capture->ReInitialize()) - { - DEBUG_ERROR("ReInitialize Failed"); - return false; - } - - if (m_capture->GetMaxFrameSize() > m_frameSize) - { - DEBUG_ERROR("Maximum frame size of %zd bytes exceeds maximum space available", m_capture->GetMaxFrameSize()); - return false; - } - - INTERLOCKED_AND8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_RESTART)); - break; + DEBUG_ERROR("ReInitialize Failed"); + return false; } - // check if the client has flagged it's ready for a frame - if (!(m_shmHeader->frame.flags & KVMFR_FRAME_FLAG_UPDATE)) - break; - - // save CPU if the client has stopped polling for updates - if (++tryCount > m_tryTarget * 400) + if (m_capture->GetMaxFrameSize() > m_frameSize) { - m_tryTarget = 250; - Sleep(100); + DEBUG_ERROR("Maximum frame size of %zd bytes exceeds maximum space available", m_capture->GetMaxFrameSize()); + return false; } + + INTERLOCKED_AND8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_RESTART)); } - int diff = (tryCount - m_lastTryCount) / 200; - m_lastTryCount = tryCount; - m_tryTarget += diff; - if (m_tryTarget < 250) - m_tryTarget = 250; - - struct FrameInfo frame = {0}; - struct CursorInfo cursor = {0}; - frame.buffer = m_frame[m_frameIndex]; - frame.bufferSize = m_frameSize; + GrabStatus result; bool ok = false; bool cursorOnly = false; @@ -226,7 +200,7 @@ bool Service::Process() for(int i = 0; i < 2; ++i) { // capture a frame of data - switch (m_capture->GrabFrame(frame, cursor)) + switch (m_capture->Capture()) { case GRAB_STATUS_OK: ok = true; @@ -298,6 +272,8 @@ bool Service::Process() return false; } + const CursorInfo & cursor = m_capture->GetCursor(); + if (cursor.updated) { EnterCriticalSection(&m_cursorCS); @@ -326,24 +302,48 @@ bool Service::Process() if (!cursorOnly) { - KVMFRFrame * fi = &m_shmHeader->frame; - + volatile KVMFRFrame * fi = &(m_shmHeader->frame); + // only update the header if the frame is new if (!repeat) { + FrameInfo frame = { 0 }; + frame.buffer = m_frame[m_frameIndex]; + frame.bufferSize = m_frameSize; + + result = m_capture->GetFrame(frame); + if (result != GRAB_STATUS_OK) + return result; + + /* don't touch the frame inforamtion until the client is done with it */ + while (fi->flags & KVMFR_FRAME_FLAG_UPDATE) + { + if (*flags & KVMFR_HEADER_FLAG_RESTART) + break; + } + 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; + } + else + { + /* don't touch the frame inforamtion until the client is done with it */ + while (fi->flags & KVMFR_FRAME_FLAG_UPDATE) + { + if (*flags & KVMFR_HEADER_FLAG_RESTART) + break; + } } - - 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; @@ -361,7 +361,7 @@ DWORD Service::CursorThread() if (WaitForSingleObject(m_cursorEvent, 1000) != WAIT_OBJECT_0) continue; - KVMFRCursor * cursor = &m_shmHeader->cursor; + volatile KVMFRCursor * cursor = &(m_shmHeader->cursor); // wait until the client is ready while (cursor->flags != 0) {