diff --git a/c-host/include/interface/capture.h b/c-host/include/interface/capture.h index 9808a44f..69bc9768 100644 --- a/c-host/include/interface/capture.h +++ b/c-host/include/interface/capture.h @@ -36,7 +36,6 @@ typedef enum CaptureFormat // frame formats CAPTURE_FMT_BGRA , CAPTURE_FMT_RGBA , - CAPTURE_FMT_ARGB , CAPTURE_FMT_RGBA10, CAPTURE_FMT_YUV420, diff --git a/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c b/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c index fbdd5e9a..c4c0a356 100644 --- a/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c +++ b/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c @@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "interface/capture.h" #include "interface/platform.h" #include "debug.h" +#include "windows/windebug.h" #include #include #include @@ -29,20 +30,20 @@ Place, Suite 330, Boston, MA 02111-1307 USA struct iface { - bool reinit; - NvFBCToSys * nvfbc; + bool reinit; + NvFBCHandle nvfbc; void * pointerShape; unsigned int pointerSize; - unsigned int width, height; + unsigned int maxWidth, maxHeight; + unsigned int width , height; uint8_t * frameBuffer; - uint8_t * diffMap; NvFBCFrameGrabInfo grabInfo; osEventHandle * frameEvent; - osEventHandle * pointerEvent; + HANDLE cursorEvent; }; static struct iface * this = NULL; @@ -75,7 +76,7 @@ static bool nvfbc_create() this = (struct iface *)calloc(sizeof(struct iface), 1); - if (!NvFBCToSysCreate(NULL, 0, &this->nvfbc)) + if (!NvFBCToSysCreate(NULL, 0, &this->nvfbc, &this->maxWidth, &this->maxHeight)) { nvfbc_free(); return false; @@ -89,14 +90,6 @@ static bool nvfbc_create() return false; } - this->pointerEvent = os_createEvent(true); - if (!this->pointerEvent) - { - DEBUG_ERROR("failed to create the pointer event"); - nvfbc_free(); - return false; - } - return true; } @@ -108,23 +101,23 @@ static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize) getDesktopSize(&this->width, &this->height); os_resetEvent(this->frameEvent); - os_resetEvent(this->pointerEvent); if (!NvFBCToSysSetup( this->nvfbc, - BUFFER_FMT_ARGB, + BUFFER_FMT_ARGB10, + false, true, - true, - DIFFMAP_BLOCKSIZE_128X128, + false, + 0, (void **)&this->frameBuffer, - (void **)&this->diffMap + NULL, + &this->cursorEvent )) { return false; } Sleep(100); - return true; } @@ -140,9 +133,6 @@ static void nvfbc_free() if (this->frameEvent) os_freeEvent(this->frameEvent); - if (this->pointerEvent) - os_freeEvent(this->pointerEvent); - free(this); this = NULL; NvFBCFree(); @@ -150,26 +140,12 @@ static void nvfbc_free() static unsigned int nvfbc_getMaxFrameSize() { - return this->width * this->height * 4; + return this->maxWidth * this->maxHeight * 4; } static CaptureResult nvfbc_capture() { - // check if the resolution has changed, if it has we need to re-init to avoid capturing - // black areas as NvFBC doesn't tell us about the change. - unsigned int width, height; - getDesktopSize(&width, &height); - if (this->width != width || this->height != height) - { - DEBUG_INFO("Resolution change detected"); - - this->reinit = true; - os_signalEvent(this->frameEvent ); - os_signalEvent(this->pointerEvent); - - return CAPTURE_RESULT_REINIT; - } - + getDesktopSize(&this->width, &this->height); NvFBCFrameGrabInfo grabInfo; CaptureResult result = NvFBCToSysCapture( this->nvfbc, @@ -183,23 +159,6 @@ static CaptureResult nvfbc_capture() if (result != CAPTURE_RESULT_OK) return result; - // NvFBC doesn't tell us when a timeout occurs, so check the diff map - // to see if anything actually changed - - const int dw = (grabInfo.dwWidth + 0x7F) >> 7; - const int dh = (grabInfo.dwHeight + 0x7F) >> 7; - bool diff = false; - for(int y = 0; y < dh && !diff; ++y) - for(int x = 0; x < dw; ++x) - if (this->diffMap[y * dw + x]) - { - diff = true; - break; - } - - if (!diff) - return CAPTURE_RESULT_TIMEOUT; - memcpy(&this->grabInfo, &grabInfo, sizeof(grabInfo)); os_signalEvent(this->frameEvent); return CAPTURE_RESULT_OK; @@ -220,24 +179,53 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame) frame->height = this->grabInfo.dwHeight; frame->pitch = this->grabInfo.dwBufferWidth * 4; frame->stride = this->grabInfo.dwBufferWidth; - frame->format = CAPTURE_FMT_BGRA; + // the bIsHDR check isn't reliable, if it's not set check a few pixels to see if + // the alpha channel has data in it. If not HDR the alpha channel should read zeros + this->grabInfo.bIsHDR = + this->grabInfo.bIsHDR || + (this->frameBuffer[3] != 0) || // top left + (this->frameBuffer[(((frame->height * frame->stride) / 2) + frame->width / 2) * 4 + 3] != 0) || // center + (this->frameBuffer[(((frame->height - 1) * frame->stride) + frame->width - 1) * 4 + 3] != 0); // bottom right + + frame->format = this->grabInfo.bIsHDR ? CAPTURE_FMT_RGBA10 : CAPTURE_FMT_BGRA; memcpy(frame->data, this->frameBuffer, frame->pitch * frame->height); return CAPTURE_RESULT_OK; } static CaptureResult nvfbc_getPointer(CapturePointer * pointer) { - if (!os_waitEvent(this->pointerEvent, TIMEOUT_INFINITE)) + while(true) { - DEBUG_ERROR("Failed to wait on the pointer event"); + bool sig = false; + switch(WaitForSingleObject((HANDLE)this->cursorEvent, INFINITE)) + { + case WAIT_OBJECT_0: + sig = true; + break; + + case WAIT_ABANDONED: + continue; + + case WAIT_TIMEOUT: + continue; + + case WAIT_FAILED: + DEBUG_WINERROR("Wait for cursor event failed", GetLastError()); + return CAPTURE_RESULT_ERROR; + } + + if (sig) + break; + + DEBUG_ERROR("Unknown wait event return code"); return CAPTURE_RESULT_ERROR; } if (this->reinit) return CAPTURE_RESULT_REINIT; - return CAPTURE_RESULT_ERROR; + return NvFBCToSysGetCursor(this->nvfbc, pointer, this->pointerShape, this->pointerSize); } struct CaptureInterface Capture_NVFBC = diff --git a/c-host/platform/Windows/capture/NVFBC/src/wrapper.cpp b/c-host/platform/Windows/capture/NVFBC/src/wrapper.cpp index bf3347f1..055b4b07 100644 --- a/c-host/platform/Windows/capture/NVFBC/src/wrapper.cpp +++ b/c-host/platform/Windows/capture/NVFBC/src/wrapper.cpp @@ -21,6 +21,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "debug.h" #include "windows/windebug.h" #include +#include #ifdef _WIN64 #define NVFBC_DLL "NvFBC64.dll" @@ -39,6 +40,13 @@ struct NVAPI NvFBC_EnableFunctionType enable; }; +struct stNvFBCHandle +{ + NvFBCToSys * nvfbc; + HANDLE cursorEvent; + int retry; +}; + static NVAPI nvapi; bool NvFBCInit() @@ -71,7 +79,13 @@ void NvFBCFree() nvapi.initialized = false; } -bool NvFBCToSysCreate(void * privData, unsigned int privDataSize, NvFBCToSys ** nvfbc) +bool NvFBCToSysCreate( + void * privData, + unsigned int privDataSize, + NvFBCHandle * handle, + unsigned int * maxWidth, + unsigned int * maxHeight +) { NvFBCCreateParams params = {0}; @@ -85,31 +99,42 @@ bool NvFBCToSysCreate(void * privData, unsigned int privDataSize, NvFBCToSys ** if (nvapi.createEx(¶ms) != NVFBC_SUCCESS) { DEBUG_ERROR("Failed to create an instance of NvFBCToSys"); - *nvfbc = NULL; + *handle = NULL; return false; } - *nvfbc = static_cast(params.pNvFBC); + *handle = (NvFBCHandle)calloc(sizeof(struct stNvFBCHandle), 1); + (*handle)->nvfbc = static_cast(params.pNvFBC); + + if (maxWidth) + *maxWidth = params.dwMaxDisplayWidth; + + if (maxHeight) + *maxHeight = params.dwMaxDisplayHeight; + return true; } -void NvFBCToSysRelease(NvFBCToSys ** nvfbc) +void NvFBCToSysRelease(NvFBCHandle * handle) { - if (!*nvfbc) + if (!*handle) return; - (*nvfbc)->NvFBCToSysRelease(); - (*nvfbc) = NULL; + (*handle)->nvfbc->NvFBCToSysRelease(); + free(*handle); + *handle = NULL; } bool NvFBCToSysSetup( - NvFBCToSys * nvfbc, + NvFBCHandle handle, enum BufferFormat format, bool hwCursor, + bool seperateCursorCapture, bool useDiffMap, enum DiffMapBlockSize diffMapBlockSize, - void ** frameBuffer, - void ** diffMap + void ** frameBuffer, + void ** diffMap, + HANDLE * cursorEvent ) { NVFBC_TOSYS_SETUP_PARAMS params = {0}; @@ -123,15 +148,19 @@ bool NvFBCToSysSetup( case BUFFER_FMT_RGB_PLANAR: params.eMode = NVFBC_TOSYS_RGB_PLANAR; break; case BUFFER_FMT_XOR : params.eMode = NVFBC_TOSYS_XOR ; break; case BUFFER_FMT_YUV444p : params.eMode = NVFBC_TOSYS_YUV444p ; break; - case BUFFER_FMT_ARGB10 : params.eMode = NVFBC_TOSYS_ARGB10 ; break; + case BUFFER_FMT_ARGB10 : + params.eMode = NVFBC_TOSYS_ARGB10; + params.bHDRRequest = TRUE; + break; default: DEBUG_INFO("Invalid format"); return false; } - params.bWithHWCursor = hwCursor ? TRUE : FALSE; - params.bDiffMap = useDiffMap ? TRUE : FALSE; + params.bWithHWCursor = hwCursor ? TRUE : FALSE; + params.bEnableSeparateCursorCapture = seperateCursorCapture ? TRUE : FALSE; + params.bDiffMap = useDiffMap ? TRUE : FALSE; switch(diffMapBlockSize) { @@ -148,16 +177,26 @@ bool NvFBCToSysSetup( params.ppBuffer = frameBuffer; params.ppDiffMap = diffMap; - return nvfbc->NvFBCToSysSetUp(¶ms) == NVFBC_SUCCESS; + NVFBCRESULT status = handle->nvfbc->NvFBCToSysSetUp(¶ms); + if (status != NVFBC_SUCCESS) + { + DEBUG_ERROR("Failed to setup NVFBCToSys"); + return false; + } + + if (cursorEvent) + *cursorEvent = params.hCursorCaptureEvent; + + return true; } CaptureResult NvFBCToSysCapture( - NvFBCToSys * nvfbc, - const unsigned int waitTime, - const unsigned int x, - const unsigned int y, - const unsigned int width, - const unsigned int height, + NvFBCHandle handle, + const unsigned int waitTime, + const unsigned int x, + const unsigned int y, + const unsigned int width, + const unsigned int height, NvFBCFrameGrabInfo * grabInfo ) { @@ -173,12 +212,29 @@ CaptureResult NvFBCToSysCapture( params.dwTargetHeight = height; params.pNvFBCFrameGrabInfo = grabInfo; - NVFBCRESULT status = nvfbc->NvFBCToSysGrabFrame(¶ms); + grabInfo->bMustRecreate = FALSE; + NVFBCRESULT status = handle->nvfbc->NvFBCToSysGrabFrame(¶ms); + if (grabInfo->bMustRecreate) + { + DEBUG_INFO("NvFBC reported recreation is required"); + return CAPTURE_RESULT_REINIT; + } + switch(status) { case NVFBC_SUCCESS: + handle->retry = 0; break; + case NVFBC_ERROR_INVALID_PARAM: + if (handle->retry < 2) + { + Sleep(100); + ++handle->retry; + return CAPTURE_RESULT_TIMEOUT; + } + return CAPTURE_RESULT_ERROR; + case NVFBC_ERROR_DYNAMIC_DISABLE: DEBUG_ERROR("NvFBC was disabled by someone else"); return CAPTURE_RESULT_ERROR; @@ -192,5 +248,57 @@ CaptureResult NvFBCToSysCapture( return CAPTURE_RESULT_ERROR; } + return CAPTURE_RESULT_OK; +} + +CaptureResult NvFBCToSysGetCursor(NvFBCHandle handle, CapturePointer * pointer, void * buffer, unsigned int size) +{ + NVFBC_CURSOR_CAPTURE_PARAMS params; + params.dwVersion = NVFBC_CURSOR_CAPTURE_PARAMS_VER; + + if (handle->nvfbc->NvFBCToSysCursorCapture(¶ms) != NVFBC_SUCCESS) + { + DEBUG_ERROR("Failed to get the cursor"); + return CAPTURE_RESULT_ERROR; + } + + pointer->x = params.dwXHotSpot; + pointer->y = params.dwYHotSpot; + pointer->width = params.dwWidth; + pointer->height = params.dwHeight; + pointer->pitch = params.dwPitch; + pointer->visible = params.bIsHwCursor; + pointer->shapeUpdate = params.bIsHwCursor; + + if (!params.bIsHwCursor) + return CAPTURE_RESULT_OK; + + switch(params.dwPointerFlags & 0x7) + { + case 0x1: + pointer->format = CAPTURE_FMT_MONO; + pointer->height *= 2; + break; + + case 0x2: + pointer->format = CAPTURE_FMT_COLOR; + break; + + case 0x4: + pointer->format = CAPTURE_FMT_MASKED; + break; + + default: + DEBUG_ERROR("Invalid/unknown pointer data format"); + return CAPTURE_RESULT_ERROR; + } + + if (params.dwBufferSize > size) + { + DEBUG_WARN("Cursor data larger then provided buffer"); + params.dwBufferSize = size; + } + + memcpy(buffer, params.pBits, params.dwBufferSize); return CAPTURE_RESULT_OK; } \ No newline at end of file diff --git a/c-host/platform/Windows/capture/NVFBC/src/wrapper.h b/c-host/platform/Windows/capture/NVFBC/src/wrapper.h index 65a57d5c..75236a2d 100644 --- a/c-host/platform/Windows/capture/NVFBC/src/wrapper.h +++ b/c-host/platform/Windows/capture/NVFBC/src/wrapper.h @@ -20,18 +20,14 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #include -#ifndef __cplusplus -typedef void * NvFBCToSys; -#else -#include -#endif - #ifdef __cplusplus extern "C" { #endif #include "interface/capture.h" +typedef struct stNvFBCHandle * NvFBCHandle; + enum BufferFormat { BUFFER_FMT_ARGB, @@ -54,29 +50,39 @@ enum DiffMapBlockSize bool NvFBCInit(); void NvFBCFree(); -bool NvFBCToSysCreate(void * privData, unsigned int privDataSize, NvFBCToSys ** nvfbc); -void NvFBCToSysRelease(NvFBCToSys ** nvfbc); +bool NvFBCToSysCreate( + void * privData, + unsigned int privDataSize, + NvFBCHandle * handle, + unsigned int * maxWidth, + unsigned int * maxHeight +); +void NvFBCToSysRelease(NvFBCHandle * handle); bool NvFBCToSysSetup( - NvFBCToSys * nvfbc, + NvFBCHandle handle, enum BufferFormat format, bool hwCursor, + bool seperateCursorCapture, bool useDiffMap, enum DiffMapBlockSize diffMapBlockSize, - void ** frameBuffer, - void ** diffMap + void ** frameBuffer, + void ** diffMap, + HANDLE * cursorEvent ); CaptureResult NvFBCToSysCapture( - NvFBCToSys * nvfbc, - const unsigned int waitTime, - const unsigned int x, - const unsigned int y, - const unsigned int width, - const unsigned int height, + NvFBCHandle handle, + const unsigned int waitTime, + const unsigned int x, + const unsigned int y, + const unsigned int width, + const unsigned int height, NvFBCFrameGrabInfo * grabInfo ); +CaptureResult NvFBCToSysGetCursor(NvFBCHandle handle, CapturePointer * pointer, void * buffer, unsigned int size); + #ifdef __cplusplus } #endif \ No newline at end of file