HRESULT STDMETHODCALLTYPE D3D11SwapPresentHook(IDXGISwapChain *swap, UINT syncInterval, UINT flags) { if(lpCurrentSwap == NULL && !bTargetAcquired) { lpCurrentSwap = swap; SetupD3D11(swap); bTargetAcquired = true; } if(lpCurrentSwap == swap) { ID3D11Device *device = NULL; HRESULT chi; if(SUCCEEDED(chi = swap->GetDevice(__uuidof(ID3D11Device), (void**)&device))) { if(!lpCurrentDevice) { lpCurrentDevice = device; /*FARPROC curRelease = GetVTable(device, (8/4)); if(curRelease != newD3D11Release) { oldD3D11Release = curRelease; newD3D11Release = (FARPROC)DeviceReleaseHook; SetVTable(device, (8/4), newD3D11Release); }*/ } ID3D11DeviceContext *context; device->GetImmediateContext(&context); if(bCapturing && bStopRequested) { ClearD3D11Data(); bStopRequested = false; } if(!bHasTextures && bCapturing) { if(dxgiFormat) { if(!hwndReceiver) hwndReceiver = FindWindow(RECEIVER_WINDOWCLASS, NULL); if(hwndReceiver) { BOOL bSuccess = DoD3D11Hook(device); if(bSuccess) { d3d11CaptureInfo.mapID = InitializeSharedMemoryGPUCapture(&texData); if(!d3d11CaptureInfo.mapID) { RUNONCE logOutput << "SwapPresentHook: creation of shared memory failed" << endl; bSuccess = false; } } if(bSuccess) bSuccess = IsWindow(hwndReceiver); if(bSuccess) { bHasTextures = true; d3d11CaptureInfo.captureType = CAPTURETYPE_SHAREDTEX; d3d11CaptureInfo.hwndSender = hwndSender; d3d11CaptureInfo.bFlip = FALSE; texData->texHandles[0] = sharedHandles[0]; texData->texHandles[1] = sharedHandles[1]; PostMessage(hwndReceiver, RECEIVER_NEWCAPTURE, 0, (LPARAM)&d3d11CaptureInfo); logOutput << "DoD3D11Hook: success"; } else { ClearD3D11Data(); } } } } if(bHasTextures) { LONGLONG frameTime; if(bCapturing) { if(texData) { if(frameTime = texData->frameTime) { LONGLONG timeVal = OSGetTimeMicroseconds(); LONGLONG timeElapsed = timeVal-lastTime; if(timeElapsed >= frameTime) { lastTime += frameTime; if(timeElapsed > frameTime*2) lastTime = timeVal; DWORD nextCapture = curCapture == 0 ? 1 : 0; ID3D11Resource *backBuffer = NULL; if(SUCCEEDED(swap->GetBuffer(0, IID_ID3D11Resource, (void**)&backBuffer))) { if(bIsMultisampled) context->ResolveSubresource(copyTextureGame, 0, backBuffer, 0, dxgiFormat); else context->CopyResource(copyTextureGame, backBuffer); ID3D10Texture2D *outputTexture = NULL; int lastRendered = -1; if(keyedMutexes[curCapture]->AcquireSync(0, 0) == WAIT_OBJECT_0) lastRendered = (int)curCapture; else if(keyedMutexes[nextCapture]->AcquireSync(0, 0) == WAIT_OBJECT_0) lastRendered = (int)nextCapture; if(lastRendered != -1) { shareDevice->CopyResource(sharedTextures[lastRendered], copyTextureIntermediary); keyedMutexes[lastRendered]->ReleaseSync(0); } texData->lastRendered = lastRendered; backBuffer->Release(); } curCapture = nextCapture; } } } } else ClearD3D11Data(); } device->Release(); context->Release(); } } gi11swapPresent.Unhook(); HRESULT hRes = swap->Present(syncInterval, flags); gi11swapPresent.Rehook(); return hRes; }
void DoD3D11Capture(IDXGISwapChain *swap) { ID3D11Device *device = NULL; HRESULT chi; if(SUCCEEDED(chi = swap->GetDevice(__uuidof(ID3D11Device), (void**)&device))) { if(!lpCurrentDevice) { lpCurrentDevice = device; /*FARPROC curRelease = GetVTable(device, (8/4)); if(curRelease != newD3D11Release) { oldD3D11Release = curRelease; newD3D11Release = (FARPROC)DeviceReleaseHook; SetVTable(device, (8/4), newD3D11Release); }*/ } ID3D11DeviceContext *context; device->GetImmediateContext(&context); if(bCapturing && bStopRequested) { ClearD3D11Data(); bCapturing = false; bStopRequested = false; } if(!bCapturing && WaitForSingleObject(hSignalRestart, 0) == WAIT_OBJECT_0) { hwndOBS = FindWindow(OBS_WINDOW_CLASS, NULL); if(hwndOBS) bCapturing = true; } if(!bHasTextures && bCapturing) { if(dxgiFormat && hwndOBS) { BOOL bSuccess = DoD3D11Hook(device); if(bSuccess) { d3d11CaptureInfo.mapID = InitializeSharedMemoryGPUCapture(&texData); if(!d3d11CaptureInfo.mapID) { RUNONCE logOutput << "SwapPresentHook: creation of shared memory failed" << endl; bSuccess = false; } } if(bSuccess) { bHasTextures = true; d3d11CaptureInfo.captureType = CAPTURETYPE_SHAREDTEX; d3d11CaptureInfo.bFlip = FALSE; texData->texHandle = (DWORD)sharedHandle; memcpy(infoMem, &d3d11CaptureInfo, sizeof(CaptureInfo)); SetEvent(hSignalReady); logOutput << "DoD3D11Hook: success" << endl; } else { ClearD3D11Data(); } } } if(bHasTextures) { LONGLONG timeVal = OSGetTimeMicroseconds(); //check keep alive state, dumb but effective if(bCapturing) { if((timeVal-keepAliveTime) > 3000000) { HANDLE hKeepAlive = OpenEvent(EVENT_ALL_ACCESS, FALSE, strKeepAlive.c_str()); if (hKeepAlive) { CloseHandle(hKeepAlive); } else { ClearD3D11Data(); bCapturing = false; } keepAliveTime = timeVal; } } LONGLONG frameTime; if(bCapturing) { if(texData) { if(frameTime = texData->frameTime) { LONGLONG timeElapsed = timeVal-lastTime; if(timeElapsed >= frameTime) { if(!IsWindow(hwndOBS)) { hwndOBS = NULL; bStopRequested = true; } if(WaitForSingleObject(hSignalEnd, 0) == WAIT_OBJECT_0) bStopRequested = true; lastTime += frameTime; if(timeElapsed > frameTime*2) lastTime = timeVal; DWORD nextCapture = curCapture == 0 ? 1 : 0; ID3D11Resource *backBuffer = NULL; if(SUCCEEDED(swap->GetBuffer(0, IID_ID3D11Resource, (void**)&backBuffer))) { if(bIsMultisampled) context->ResolveSubresource(copyTextureGame, 0, backBuffer, 0, dxgiFormat); else context->CopyResource(copyTextureGame, backBuffer); backBuffer->Release(); } curCapture = nextCapture; } } } } else ClearD3D11Data(); } device->Release(); context->Release(); } }
void CaptureDDraw() { //RUNEVERYRESET logOutput << CurrentTimeString() << "called CaptureDDraw()" << endl; if (bCapturing && WaitForSingleObject(hSignalEnd, 0) == WAIT_OBJECT_0) { //logOutput << CurrentTimeString() << "not capturing or received hSignalEnd" << endl; bStopRequested = true; } if (bCapturing && !IsWindow(hwndOBS)) { //logOutput << CurrentTimeString() << "not capturing or OBS window not found" << endl; hwndOBS = NULL; bStopRequested = true; } if (bStopRequested) { CleanUpDDraw(); bCapturing = false; bStopRequested = false; } if (!bCapturing && WaitForSingleObject(hSignalRestart, 0) == WAIT_OBJECT_0) { //logOutput << CurrentTimeString() << "capturing and received hSignalRestart" << endl; hwndOBS = FindWindow(OBS_WINDOW_CLASS, NULL); if (hwndOBS) { logOutput << CurrentTimeString() << "received restart event, capturing" << endl; bCapturing = true; } else { logOutput << CurrentTimeString() << "received restart event, but couldn't find window" << endl; } } LONGLONG timeVal = OSGetTimeMicroseconds(); //check keep alive state, dumb but effective if (bCapturing) { if (!keepAliveTime) keepAliveTime = timeVal; if ((timeVal - keepAliveTime) > 5000000) { HANDLE hKeepAlive = OpenEvent(EVENT_ALL_ACCESS, FALSE, strKeepAlive.c_str()); if (hKeepAlive) { CloseHandle(hKeepAlive); } else { logOutput << CurrentTimeString() << "Keepalive no longer found on ddraw, freeing capture data" << endl; CleanUpDDraw(); bCapturing = false; } keepAliveTime = timeVal; } } if (bHasTextures) { LONGLONG frameTime; if (bCapturing) { if (copyData) { if (frameTime = copyData->frameTime) { LONGLONG timeElapsed = timeVal - lastTime; if (timeElapsed >= frameTime) { lastTime += frameTime; if (timeElapsed > frameTime * 2) lastTime = timeVal; //logOutput << CurrentTimeString() << "CaptureDDraw: capturing screen from 0x" << g_frontSurface << endl; HRESULT hr; ddrawSurfaceBlt.Unhook(); hr = ddCaptures[curCapture]->Blt(NULL, g_frontSurface, NULL, DDBLT_ASYNC, NULL); ddrawSurfaceBlt.Rehook(); if (SUCCEEDED(hr)) { DWORD nextCapture = (curCapture == NUM_BUFFERS - 1) ? 0 : (curCapture + 1); curCPUTexture = curCapture; curCapture = nextCapture; SetEvent(hCopyEvent); } else { printDDrawError(hr, "CaptureDDraw"); } //logOutput << CurrentTimeString() << "CaptureDDraw: finished capturing" << endl; } } } } } }
void DoD3D101Capture(IDXGISwapChain *swap) { HRESULT hRes; ID3D10Device *device = NULL; if(SUCCEEDED(swap->GetDevice(__uuidof(ID3D10Device), (void**)&device))) { if(bCapturing && WaitForSingleObject(hSignalEnd, 0) == WAIT_OBJECT_0) bStopRequested = true; if(bCapturing && !IsWindow(hwndOBS)) { hwndOBS = NULL; bStopRequested = true; } if(!lpCurrentDevice) { lpCurrentDevice = device; /*FARPROC oldRelease = GetVTable(device, (8/4)); if(oldRelease != newD3D10Release) { oldD3D10Release = oldRelease; newD3D10Release = ConvertClassProcToFarproc((CLASSPROC)&D3D101Override::DeviceReleaseHook); SetVTable(device, (8/4), newD3D10Release); }*/ } if(bCapturing && bStopRequested) { RUNEVERYRESET logOutput << CurrentTimeString() << "stop requested, terminating d3d10.1 capture" << endl; ClearD3D101Data(); bCapturing = false; bStopRequested = false; } if(!bCapturing && WaitForSingleObject(hSignalRestart, 0) == WAIT_OBJECT_0) { hwndOBS = FindWindow(OBS_WINDOW_CLASS, NULL); if(hwndOBS) bCapturing = true; } if(!bHasTextures && bCapturing) { if(dxgiFormat && hwndOBS) { BOOL bSuccess = DoD3D101Hook(device); if(bSuccess) { d3d101CaptureInfo.mapID = InitializeSharedMemoryGPUCapture(&texData); if(!d3d101CaptureInfo.mapID) bSuccess = false; } if(bSuccess) { bHasTextures = true; d3d101CaptureInfo.captureType = CAPTURETYPE_SHAREDTEX; d3d101CaptureInfo.bFlip = FALSE; texData->texHandle = (DWORD)sharedHandle; memcpy(infoMem, &d3d101CaptureInfo, sizeof(CaptureInfo)); SetEvent(hSignalReady); logOutput << CurrentTimeString() << "DoD3D101Hook: success" << endl; } else { ClearD3D101Data(); } } } LONGLONG timeVal = OSGetTimeMicroseconds(); //check keep alive state, dumb but effective if(bCapturing) { if (!keepAliveTime) keepAliveTime = timeVal; if((timeVal-keepAliveTime) > 5000000) { HANDLE hKeepAlive = OpenEvent(EVENT_ALL_ACCESS, FALSE, strKeepAlive.c_str()); if (hKeepAlive) { CloseHandle(hKeepAlive); } else { ClearD3D101Data(); logOutput << CurrentTimeString() << "Keepalive no longer found on d3d10.1, freeing capture data" << endl; bCapturing = false; } keepAliveTime = timeVal; } } if(bHasTextures) { LONGLONG frameTime; if(bCapturing) { if(texData) { if(frameTime = texData->frameTime) { LONGLONG timeElapsed = timeVal-lastTime; if(timeElapsed >= frameTime) { lastTime += frameTime; if(timeElapsed > frameTime*2) lastTime = timeVal; DWORD nextCapture = curCapture == 0 ? 1 : 0; ID3D10Resource *backBuffer = NULL; if(SUCCEEDED(hRes = swap->GetBuffer(0, IID_ID3D10Resource, (void**)&backBuffer))) { if(bIsMultisampled) device->ResolveSubresource(copyD3D101TextureGame, 0, backBuffer, 0, dxgiFormat); else device->CopyResource(copyD3D101TextureGame, backBuffer); RUNEVERYRESET logOutput << CurrentTimeString() << "successfully capturing d3d10.1 frames via GPU" << endl; backBuffer->Release(); } else { RUNEVERYRESET logOutput << CurrentTimeString() << "DoD3D101Capture: swap->GetBuffer failed: result = " << UINT(hRes) << endl; } curCapture = nextCapture; } } } } else { RUNEVERYRESET logOutput << CurrentTimeString() << "no longer capturing, terminating d3d10.1 capture" << endl; ClearD3D101Data(); } } } SafeRelease(device); }
void HandleGLSceneUpdate(HDC hDC) { if(!bTargetAcquired && hdcAcquiredDC == NULL) { logOutput << CurrentTimeString() << "setting up gl data" << endl; PIXELFORMATDESCRIPTOR pfd; hwndTarget = WindowFromDC(hDC); int pixFormat = GetPixelFormat(hDC); DescribePixelFormat(hDC, pixFormat, sizeof(pfd), &pfd); if(pfd.cColorBits == 32 && hwndTarget) { bTargetAcquired = true; hdcAcquiredDC = hDC; glcaptureInfo.format = GS_BGR; } OSInitializeTimer(); } if(hDC == hdcAcquiredDC) { if(bCapturing && WaitForSingleObject(hSignalEnd, 0) == WAIT_OBJECT_0) bStopRequested = true; if(bCapturing && !IsWindow(hwndOBS)) { hwndOBS = NULL; bStopRequested = true; } if(bCapturing && bStopRequested) { RUNEVERYRESET logOutput << CurrentTimeString() << "stop requested, terminating gl capture" << endl; ClearGLData(); bCapturing = false; bStopRequested = false; bReacquiring = false; } if(!bCapturing && WaitForSingleObject(hSignalRestart, 0) == WAIT_OBJECT_0) { hwndOBS = FindWindow(OBS_WINDOW_CLASS, NULL); if(hwndOBS) bCapturing = true; } RECT rc; GetClientRect(hwndTarget, &rc); if(bCapturing && bReacquiring) { if(lastCX != rc.right || lastCY != rc.bottom) //reset if continuing to size within the 3 seconds { reacquireStart = OSGetTimeMicroseconds(); lastCX = rc.right; lastCY = rc.bottom; } if(OSGetTimeMicroseconds()-reacquireTime >= 3000000) { //3 second to reacquire RUNEVERYRESET logOutput << CurrentTimeString() << "reacquiring gl due to resize..." << endl; bReacquiring = false; } else { return; } } if(bCapturing && (!bHasTextures || rc.right != glcaptureInfo.cx || rc.bottom != glcaptureInfo.cy)) { if (!rc.right || !rc.bottom) return; if(bHasTextures) //resizing { ClearGLData(); bReacquiring = true; reacquireStart = OSGetTimeMicroseconds(); lastCX = rc.right; lastCY = rc.bottom; return; } else { if(hwndOBS) DoGLCPUHook(rc); else ClearGLData(); } } LONGLONG timeVal = OSGetTimeMicroseconds(); //check keep alive state, dumb but effective if(bCapturing) { if (!keepAliveTime) keepAliveTime = timeVal; if((timeVal-keepAliveTime) > 5000000) { HANDLE hKeepAlive = OpenEvent(EVENT_ALL_ACCESS, FALSE, strKeepAlive.c_str()); if (hKeepAlive) { CloseHandle(hKeepAlive); } else { ClearGLData(); logOutput << CurrentTimeString() << "Keepalive no longer found on gl, freeing capture data" << endl; bCapturing = false; } keepAliveTime = timeVal; } } if(bHasTextures) { LONGLONG frameTime; if(bCapturing) { if(copyData) { if(frameTime = copyData->frameTime) { LONGLONG timeElapsed = timeVal-lastTime; if(timeElapsed >= frameTime) { lastTime += frameTime; if(timeElapsed > frameTime*2) lastTime = timeVal; GLuint texture = gltextures[curCapture]; DWORD nextCapture = (curCapture == NUM_BUFFERS-1) ? 0 : (curCapture+1); glReadBuffer(GL_BACK); glBindBuffer(GL_PIXEL_PACK_BUFFER, texture); if(glLockedTextures[curCapture]) { OSEnterMutex(glDataMutexes[curCapture]); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glLockedTextures[curCapture] = false; OSLeaveMutex(glDataMutexes[curCapture]); } glReadPixels(0, 0, glcaptureInfo.cx, glcaptureInfo.cy, GL_BGRA, GL_UNSIGNED_BYTE, 0); //---------------------------------- glBindBuffer(GL_PIXEL_PACK_BUFFER, gltextures[nextCapture]); pCopyData = (void*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); if(pCopyData) { curCPUTexture = nextCapture; glLockedTextures[nextCapture] = true; RUNEVERYRESET logOutput << CurrentTimeString() << "successfully capturing gl frames via RAM" << endl; SetEvent(hCopyEvent); } else { RUNEVERYRESET logOutput << CurrentTimeString() << "one or more gl frames failed to capture for some reason" << endl; } //---------------------------------- glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); curCapture = nextCapture; } } } } else { RUNEVERYRESET logOutput << CurrentTimeString() << "no longer capturing, terminating gl capture" << endl; ClearGLData(); } } } }