void CheckDDrawCapture() { EnterCriticalSection(&ddrawMutex); ddrawSurfaceUnlock.Rehook(true); ddrawSurfaceFlip.Rehook(true); ddrawSurfaceBlt.Rehook(true); LeaveCriticalSection(&ddrawMutex); }
void HookAll() { ddrawSurfaceCreate.Rehook(); ddrawSurfaceRestore.Rehook(); ddrawSurfaceRelease.Rehook(); ddrawSurfaceSetPalette.Rehook(); ddrawPaletteSetEntries.Rehook(); }
bool InitD3D11Capture() { bool bSuccess = false; HMODULE hD3D11Dll = GetModuleHandle(TEXT("d3d11.dll")); if(hD3D11Dll) { D3D11CREATEPROC d3d11Create = (D3D11CREATEPROC)GetProcAddress(hD3D11Dll, "D3D11CreateDeviceAndSwapChain"); if(d3d11Create) { DXGI_SWAP_CHAIN_DESC swapDesc; ZeroMemory(&swapDesc, sizeof(swapDesc)); swapDesc.BufferCount = 2; swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swapDesc.BufferDesc.Width = 2; swapDesc.BufferDesc.Height = 2; swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapDesc.OutputWindow = hwndSender; swapDesc.SampleDesc.Count = 1; swapDesc.Windowed = TRUE; IDXGISwapChain *swap; ID3D11Device *device; ID3D11DeviceContext *context; D3D_FEATURE_LEVEL desiredLevel = D3D_FEATURE_LEVEL_11_0; D3D_FEATURE_LEVEL receivedLevel; HRESULT hErr; if(SUCCEEDED(hErr = (*d3d11Create)(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &desiredLevel, 1, D3D11_SDK_VERSION, &swapDesc, &swap, &device, &receivedLevel, &context))) { bSuccess = true; UPARAM *vtable = *(UPARAM**)swap; gi11swapPresent.Hook((FARPROC)*(vtable+(32/4)), ConvertClassProcToFarproc((CLASSPROC)&D3D11Override::SwapPresentHook)); gi11swapResizeBuffers.Hook((FARPROC)*(vtable+(52/4)), ConvertClassProcToFarproc((CLASSPROC)&D3D11Override::SwapResizeBuffersHook)); SafeRelease(swap); SafeRelease(device); SafeRelease(context); gi11swapPresent.Rehook(); gi11swapResizeBuffers.Rehook(); } } } return bSuccess; }
HRESULT STDMETHODCALLTYPE Blt(LPDIRECTDRAWSURFACE7 surface, LPRECT lpDestRect, LPDIRECTDRAWSURFACE7 lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx) { //logOutput << CurrentTimeString() << "Hooked Blt()" << endl; EnterCriticalSection(&ddrawMutex); ddrawSurfaceBlt.Unhook(); HRESULT hr = surface->Blt(lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); ddrawSurfaceBlt.Rehook(); if (SUCCEEDED(hr)) { if (!g_bUseFlipMethod) { if (getFrontSurface(surface)) { CaptureDDraw(); } } } LeaveCriticalSection(&ddrawMutex); return hr; }
HRESULT STDMETHODCALLTYPE CreateSurface(IDirectDraw7* ddInterface, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPDIRECTDRAWSURFACE7 *lplpDDSurface, IUnknown *pUnkOuter) { //logOutput << CurrentTimeString() << "Hooked CreateSurface()" << endl; if (!g_ddInterface) { if (ddInterface->QueryInterface(IID_IDirectDraw, (LPVOID*)&g_ddInterface) == S_OK) { logOutput << CurrentTimeString() << "IDirectDraw::CreateSurface: got DDInterface pointer" << endl; } else { logOutput << CurrentTimeString() << "IDirectDraw::CreateSurface: could not query DirectDraw interface" << endl; } } ddrawSurfaceCreate.Unhook(); HRESULT hRes = ddInterface->CreateSurface(lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); ddrawSurfaceCreate.Rehook(); if (hRes == DD_OK) { if (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { logOutput << CurrentTimeString() << "IDirectDraw::CreateSurface: Primary surface created at 0x" << *lplpDDSurface << endl; getFrontSurface(*lplpDDSurface); } } else printDDrawError(hRes, "CreateSurface"); return hRes; }
BOOL WINAPI wglSwapLayerBuffersHook(HDC hDC, UINT fuPlanes) { HandleGLSceneUpdate(hDC); glHookSwapLayerBuffers.Unhook(); BOOL bResult = jimglSwapLayerBuffers(hDC, fuPlanes); glHookSwapLayerBuffers.Rehook(); return bResult; }
BOOL WINAPI wglDeleteContextHook(HGLRC hRC) { HandleGLSceneDestroy(); glHookDeleteContext.Unhook(); BOOL bResult = jimglDeleteContext(hRC); glHookDeleteContext.Rehook(); return bResult; }
BOOL WINAPI SwapBuffersHook(HDC hDC) { HandleGLSceneUpdate(hDC); glHookSwapBuffers.Unhook(); BOOL bResult = SwapBuffers(hDC); glHookSwapBuffers.Rehook(); return bResult; }
inline HRESULT STDMETHODCALLTYPE UnlockSurface(LPDIRECTDRAWSURFACE7 surface, LPRECT data) { //logOutput << CurrentTimeString() << "Called UnlockSurface" << endl; // standard handler if (!bTargetAcquired) { ddrawSurfaceUnlock.Unhook(); HRESULT hr = surface->Unlock(data); ddrawSurfaceUnlock.Rehook(); return hr; } // use mutex lock to prevent memory corruption when calling Unhook/Rehook from multiple threads HANDLE mutex = OpenMutex(SYNCHRONIZE, FALSE, mutexName); if (!mutex) { logOutput << CurrentTimeString() << "Could not open mutex - Error(" << GetLastError() << ')' << endl; return DDERR_GENERIC; } DWORD ret = WaitForSingleObject(mutex, INFINITE); if (ret == WAIT_OBJECT_0) { ddrawSurfaceUnlock.Unhook(); HRESULT hr = surface->Unlock(data); ddrawSurfaceUnlock.Rehook(); ReleaseMutex(mutex); CloseHandle(mutex); return hr; } else { logOutput << CurrentTimeString() << "error while waiting for unlock-mutex to get signaled" << endl; logOutput << CurrentTimeString() << "GetLastError: " << GetLastError() << endl; CloseHandle(mutex); return DDERR_GENERIC; } }
void ReloadPrimarySurfacePaletteEntries() { if (!primary_surface_palette_ref) return; HRESULT err; ddrawPaletteSetEntries.Unhook(); if (FAILED(err = primary_surface_palette_ref->SetEntries(0, 0, numEntries, entries))) { logOutput << CurrentTimeString() << "ReloadPrimarySurfacePaletteEntries(): could not set entires" << endl; printDDrawError(err); } ddrawPaletteSetEntries.Rehook(); }
HRESULT STDMETHODCALLTYPE SetPalette(LPDIRECTDRAWSURFACE7 surface, LPDIRECTDRAWPALETTE lpDDPalette) { //logOutput << CurrentTimeString() << "Hooked SetPalette()" << endl; ddrawSurfaceSetPalette.Unhook(); HRESULT hr = surface->SetPalette(lpDDPalette); ddrawSurfaceSetPalette.Rehook(); if (getFrontSurface(surface)) { if (lpDDPalette) lpDDPalette->AddRef(); SetupPalette(lpDDPalette); } return hr; }
HRESULT STDMETHODCALLTYPE PaletteSetEntries(LPDIRECTDRAWPALETTE palette, DWORD dwFlags, DWORD dwStartingEntry, DWORD dwCount, LPPALETTEENTRY lpEntries) { //logOutput << CurrentTimeString() << "Hooked SetEntries()" << endl; ddrawPaletteSetEntries.Unhook(); HRESULT hr = palette->SetEntries(dwFlags, dwStartingEntry, dwCount, lpEntries); ddrawPaletteSetEntries.Rehook(); // update buffer palette if (SUCCEEDED(hr)) { if (g_CurrentPalette.bInitialized) { memcpy(g_CurrentPalette.entries + dwStartingEntry, lpEntries, 4 * dwCount); // each entry is 4 bytes if DDCAPS_8BITENTRIES flag is not set } } return hr; }
HRESULT STDMETHODCALLTYPE D3D11SwapResizeBuffersHook(IDXGISwapChain *swap, UINT bufferCount, UINT width, UINT height, DXGI_FORMAT giFormat, UINT flags) { ClearD3D11Data(); lpCurrentSwap = NULL; lpCurrentDevice = NULL; bTargetAcquired = false; gi11swapResizeBuffers.Unhook(); HRESULT hRes = swap->ResizeBuffers(bufferCount, width, height, giFormat, flags); gi11swapResizeBuffers.Rehook(); /*if(lpCurrentSwap == NULL && !bTargetAcquired) { lpCurrentSwap = swap; bTargetAcquired = true; } if(lpCurrentSwap == swap) SetupD3D11(swap);*/ return hRes; }
HRESULT STDMETHODCALLTYPE Restore(LPDIRECTDRAWSURFACE7 surface) { //logOutput << CurrentTimeString() << "Hooked Restore()" << endl; ddrawSurfaceRestore.Unhook(); HRESULT hr = surface->Restore(); if (bHasTextures) { if (surface == g_frontSurface) { logOutput << CurrentTimeString() << "SurfaceRestore: restoring offscreen buffers" << endl; bool success = true; for (UINT i = 0; i < NUM_BUFFERS; i++) { HRESULT err; if (FAILED(err = ddCaptures[i]->Restore())) { logOutput << CurrentTimeString() << "SurfaceRestore: error restoring offscreen buffer" << endl; printDDrawError(err, "Restore"); success = false; } } if (!success) { CleanUpDDraw(); } } } ddrawSurfaceRestore.Rehook(); if (!bHasTextures) { getFrontSurface(surface); } return hr; }
HRESULT STDMETHODCALLTYPE Flip(LPDIRECTDRAWSURFACE7 surface, LPDIRECTDRAWSURFACE7 lpDDSurface, DWORD flags) { //logOutput << CurrentTimeString() << "Hooked Flip()" << endl; HRESULT hr; EnterCriticalSection(&ddrawMutex); ddrawSurfaceFlip.Unhook(); hr = surface->Flip(lpDDSurface, flags); ddrawSurfaceFlip.Rehook(); g_bUseFlipMethod = true; if (getFrontSurface(surface)) { CaptureDDraw(); } LeaveCriticalSection(&ddrawMutex); return hr; }
ULONG STDMETHODCALLTYPE Release(LPDIRECTDRAWSURFACE7 surface) { //logOutput << CurrentTimeString() << "Hooked Release()" << endl; ddrawSurfaceRelease.Unhook(); /* if(surface == g_frontSurface) { logOutput << CurrentTimeString() << "Releasing primary surface 0x" << surface << endl; surface->AddRef(); ULONG refCount = surface->Release(); if(refCount == 1) { logOutput << CurrentTimeString() << "Freeing primary surface" << endl; g_frontSurface = NULL; bTargetAcquired = false; CleanUpDDraw(); } } */ ULONG refCount = surface->Release(); ddrawSurfaceRelease.Rehook(); if (surface == g_frontSurface) { if (refCount == 0) { logOutput << CurrentTimeString() << "Freeing primary surface" << endl; CleanUpDDraw(); } } return refCount; }
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; } } } } } }
HRESULT STDMETHODCALLTYPE SwapPresentHook(UINT syncInterval, UINT flags) { IDXGISwapChain *swap = (IDXGISwapChain*)this; 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; oldD3D11Release = GetVTable(device, (8/4)); newD3D11Release = ConvertClassProcToFarproc((CLASSPROC)&D3D11Override::DeviceReleaseHook); SetVTable(device, (8/4), newD3D11Release); } ID3D11DeviceContext *context; device->GetImmediateContext(&context); if(!bHasTextures && bCapturing) { if(dxgiFormat) { if(!hwndReceiver) hwndReceiver = FindWindow(RECEIVER_WINDOWCLASS, NULL); if(hwndReceiver) { D3D11_TEXTURE2D_DESC texDesc; ZeroMemory(&texDesc, sizeof(texDesc)); texDesc.Width = d3d11CaptureInfo.cx; texDesc.Height = d3d11CaptureInfo.cy; texDesc.MipLevels = 1; texDesc.ArraySize = 1; texDesc.Format = dxgiFormat; texDesc.SampleDesc.Count = 1; texDesc.Usage = D3D11_USAGE_STAGING; texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; bool bSuccess = true; UINT pitch; for(UINT i=0; i<2; i++) { HRESULT ching; if(FAILED(ching = device->CreateTexture2D(&texDesc, NULL, &d3d11Textures[i]))) { bSuccess = false; break; } if(i == 0) { ID3D11Resource *resource; if(FAILED(d3d11Textures[i]->QueryInterface(__uuidof(ID3D11Resource), (void**)&resource))) { bSuccess = false; break; } D3D11_MAPPED_SUBRESOURCE map; if(FAILED(context->Map(resource, 0, D3D11_MAP_READ, 0, &map))) { bSuccess = false; break; } pitch = map.RowPitch; context->Unmap(resource, 0); resource->Release(); } } if(bSuccess) { d3d11CaptureInfo.mapID = InitializeSharedMemory(pitch*d3d11CaptureInfo.cy, &d3d11CaptureInfo.mapSize, ©Data, textureBuffers); if(!d3d11CaptureInfo.mapID) bSuccess = false; } if(bSuccess) { bHasTextures = true; d3d11CaptureInfo.captureType = CAPTURETYPE_MEMORY; d3d11CaptureInfo.hwndSender = hwndSender; d3d11CaptureInfo.pitch = pitch; d3d11CaptureInfo.bFlip = FALSE; PostMessage(hwndReceiver, RECEIVER_NEWCAPTURE, 0, (LPARAM)&d3d11CaptureInfo); } else { for(UINT i=0; i<2; i++) { SafeRelease(d3d11Textures[i]); if(textureBuffers[i]) { free(textureBuffers[i]); textureBuffers[i] = NULL; } } } } } } if(bHasTextures) { if(bCapturing) { DWORD nextCapture = curCapture == 0 ? 1 : 0; ID3D11Texture2D *texture = d3d11Textures[curCapture]; ID3D11Resource *backBuffer = NULL; if(SUCCEEDED(swap->GetBuffer(0, IID_ID3D11Resource, (void**)&backBuffer))) { if(bIsMultisampled) context->ResolveSubresource(texture, 0, backBuffer, 0, dxgiFormat); else context->CopyResource(texture, backBuffer); backBuffer->Release(); ID3D11Texture2D *lastTexture = d3d11Textures[nextCapture]; ID3D11Resource *resource; if(SUCCEEDED(lastTexture->QueryInterface(__uuidof(ID3D11Resource), (void**)&resource))) { D3D11_MAPPED_SUBRESOURCE map; if(SUCCEEDED(context->Map(resource, 0, D3D11_MAP_READ, 0, &map))) { LPBYTE *pTextureBuffer = NULL; int lastRendered = -1; //under no circumstances do we -ever- allow a stall if(WaitForSingleObject(textureMutexes[curCapture], 0) == WAIT_OBJECT_0) lastRendered = (int)curCapture; else if(WaitForSingleObject(textureMutexes[nextCapture], 0) == WAIT_OBJECT_0) lastRendered = (int)nextCapture; if(lastRendered != -1) { SSECopy(textureBuffers[lastRendered], map.pData, map.RowPitch*d3d11CaptureInfo.cy); ReleaseMutex(textureMutexes[lastRendered]); } context->Unmap(resource, 0); copyData->lastRendered = (UINT)lastRendered; } resource->Release(); } } curCapture = nextCapture; } else ClearD3D11Data(); } device->Release(); context->Release(); } } gi11swapPresent.Unhook(); HRESULT hRes = swap->Present(syncInterval, flags); gi11swapPresent.Rehook(); return hRes; }
bool InitD3D11Capture() { bool bSuccess = false; HMODULE hD3D11Dll = GetModuleHandle(TEXT("d3d11.dll")); if(hD3D11Dll) { D3D11CREATEPROC d3d11Create = (D3D11CREATEPROC)GetProcAddress(hD3D11Dll, "D3D11CreateDeviceAndSwapChain"); if(d3d11Create) { DXGI_SWAP_CHAIN_DESC swapDesc; ZeroMemory(&swapDesc, sizeof(swapDesc)); swapDesc.BufferCount = 2; swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapDesc.BufferDesc.Width = 2; swapDesc.BufferDesc.Height = 2; swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapDesc.OutputWindow = hwndSender; swapDesc.SampleDesc.Count = 1; swapDesc.Windowed = TRUE; IDXGISwapChain *swap; ID3D11Device *device; ID3D11DeviceContext *context; D3D_FEATURE_LEVEL desiredLevels[6] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1, }; D3D_FEATURE_LEVEL receivedLevel; HRESULT hErr; if(SUCCEEDED(hErr = (*d3d11Create)(NULL, D3D_DRIVER_TYPE_NULL, NULL, 0, desiredLevels, 6, D3D11_SDK_VERSION, &swapDesc, &swap, &device, &receivedLevel, &context))) { bSuccess = true; UPARAM *vtable = *(UPARAM**)swap; gi11swapPresent.Hook((FARPROC)*(vtable+(32/4)), (FARPROC)D3D11SwapPresentHook); gi11swapResizeBuffers.Hook((FARPROC)*(vtable+(52/4)), (FARPROC)D3D11SwapResizeBuffersHook); SafeRelease(swap); SafeRelease(device); SafeRelease(context); gi11swapPresent.Rehook(); gi11swapResizeBuffers.Rehook(); } else { RUNONCE logOutput << "InitD3D11Capture: D3D11CreateDeviceAndSwapChain definitely failed, result = " << UINT(hErr) << endl; } } else { RUNONCE logOutput << "InitD3D11Capture: could not get address of D3D11CreateDeviceAndSwapChain" << endl; } } return bSuccess; }
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; }
// set frontSurface to lpDDSurface if lpDDSurface is primary // returns true if frontSurface is set // returns false if frontSurface is NULL and lpDDSurface is not primary bool getFrontSurface(LPDIRECTDRAWSURFACE7 lpDDSurface) { //logOutput << CurrentTimeString() << "called getFrontSurface" << endl; if (!lpDDSurface) { //logOutput << CurrentTimeString() << "lpDDSurface null" << endl; return false; } if (!g_ddInterface) { LPDIRECTDRAWSURFACE7 dummy; if (lpDDSurface->QueryInterface(IID_IDirectDrawSurface7, (LPVOID*)&dummy) == S_OK) { IUnknown* Unknown; HRESULT err; if (FAILED(err = dummy->GetDDInterface((LPVOID*)&Unknown))) { logOutput << CurrentTimeString() << "getFrontSurface: could not get DirectDraw interface" << endl; printDDrawError(err, "getFrontSurface"); } else { if (Unknown->QueryInterface(IID_IDirectDraw7, (LPVOID*)&g_ddInterface) == S_OK) { logOutput << CurrentTimeString() << "Got DirectDraw interface pointer" << endl; } else { logOutput << CurrentTimeString() << "Query of DirectDraw interface failed" << endl; } } ddrawSurfaceRelease.Unhook(); dummy->Release(); ddrawSurfaceRelease.Rehook(); } } if (!bTargetAcquired) { DDSCAPS2 caps; if (SUCCEEDED(lpDDSurface->GetCaps(&caps))) { //logOutput << CurrentTimeString() << "checking if surface is primary" << endl; if (caps.dwCaps & DDSCAPS_PRIMARYSURFACE) { logOutput << CurrentTimeString() << "found primary surface" << endl; g_frontSurface = lpDDSurface; if (!SetupDDraw()) { return false; } else { bTargetAcquired = true; } } } else { logOutput << CurrentTimeString() << "could not retrieve caps" << endl; } } return lpDDSurface == g_frontSurface; }
bool SetupDDraw() { logOutput << CurrentTimeString() << "called SetupDDraw()" << endl; if (!g_ddInterface) { logOutput << CurrentTimeString() << "SetupDDraw: DirectDraw interface not set, returning" << endl; return false; } bool bSuccess = true; bKillThread = false; if (hCopyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CopyDDrawTextureThread, NULL, 0, NULL)) { if (!(hCopyEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { logOutput << CurrentTimeString() << "SetupDDraw: CreateEvent failed, GetLastError = " << GetLastError() << endl; bSuccess = false; } } else { logOutput << CurrentTimeString() << "SetupDDraw: CreateThread failed, GetLastError = " << GetLastError() << endl; bSuccess = false; } if (bSuccess) { if (!ddUnlockFctMutex) { ddUnlockFctMutex = CreateMutex(NULL, FALSE, mutexName); if (!ddUnlockFctMutex) { RUNEVERYRESET logOutput << CurrentTimeString() << "SetupDDraw: CreateMutex failed, GetLastError = " << GetLastError() << endl; bSuccess = false; } } } if (bSuccess && !g_frontSurface) { RUNEVERYRESET logOutput << "SetupDDraw: frontSurface and surface descriptor not set, returning" << endl; CleanUpDDraw(); return false; } else if (bSuccess) { LPDIRECTDRAWPALETTE palette = NULL; HRESULT err; if (SUCCEEDED(err = g_frontSurface->GetPalette(&palette))) { if (palette) SetupPalette(palette); } else if (err == DDERR_NOPALETTEATTACHED) { //logOutput << CurrentTimeString() << "No palette attached to primary surface" << endl; } else { logOutput << CurrentTimeString() << "Error retrieving palette" << endl; printDDrawError(err, "getFrontSurface"); } } if (bSuccess && !g_surfaceDesc) { logOutput << CurrentTimeString() << "SetupDDraw: no surface descriptor found, creating a new one (not an error)" << endl; g_surfaceDesc = new DDSURFACEDESC2; g_surfaceDesc->dwSize = sizeof(DDSURFACEDESC); HRESULT hr; if (FAILED(hr = ((LPDIRECTDRAWSURFACE)g_frontSurface)->GetSurfaceDesc((LPDDSURFACEDESC)g_surfaceDesc))) { g_surfaceDesc->dwSize = sizeof(DDSURFACEDESC2); if (FAILED(g_frontSurface->GetSurfaceDesc(g_surfaceDesc))) { logOutput << CurrentTimeString() << "SetupDDraw: error getting surface descriptor" << endl; printDDrawError(hr, "SetupDDraw"); bSuccess = false; } } } if (bSuccess && g_surfaceDesc) { const DDPIXELFORMAT& pf = g_surfaceDesc->ddpfPixelFormat; if (pf.dwFlags & DDPF_RGB) { if (pf.dwRGBBitCount == 16) { logOutput << CurrentTimeString() << "SetupDDraw: found 16bit format (using R5G6B5 conversion)" << endl; g_bConvert16to32 = true; } else if (pf.dwRGBBitCount == 32) { logOutput << CurrentTimeString() << "SetupDDraw: found 32bit format (using plain copy)" << endl; g_bUse32bitCapture = true; } } else if (pf.dwFlags & (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED1)) { logOutput << CurrentTimeString() << "SetupDDraw: front surface uses palette indices" << endl; } } if (bSuccess) { logOutput << CurrentTimeString() << "SetupDDraw: primary surface width = " << g_surfaceDesc->dwWidth << ", height = " << g_surfaceDesc->dwHeight << endl; g_dwSize = g_surfaceDesc->lPitch*g_surfaceDesc->dwHeight; ddrawCaptureInfo.captureType = CAPTURETYPE_MEMORY; ddrawCaptureInfo.cx = g_surfaceDesc->dwWidth; ddrawCaptureInfo.cy = g_surfaceDesc->dwHeight; ddrawCaptureInfo.pitch = 4 * ddrawCaptureInfo.cx; ddrawCaptureInfo.hwndCapture = (DWORD)hwndSender; ddrawCaptureInfo.format = GS_BGRA; DWORD g_dwCaptureSize = ddrawCaptureInfo.pitch*ddrawCaptureInfo.cy; ddrawCaptureInfo.bFlip = FALSE; ddrawCaptureInfo.mapID = InitializeSharedMemoryCPUCapture(g_dwCaptureSize, &ddrawCaptureInfo.mapSize, ©Data, textureBuffers); memcpy(infoMem, &ddrawCaptureInfo, sizeof(CaptureInfo)); DDSURFACEDESC2 captureDesc; ZeroMemory(&captureDesc, sizeof(captureDesc)); captureDesc.dwSize = sizeof(DDSURFACEDESC2); captureDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_PITCH; captureDesc.dwWidth = g_surfaceDesc->dwWidth; captureDesc.dwHeight = g_surfaceDesc->dwHeight; captureDesc.lPitch = g_surfaceDesc->lPitch; captureDesc.ddpfPixelFormat = g_surfaceDesc->ddpfPixelFormat; captureDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; HRESULT err; ddrawSurfaceCreate.Unhook(); for (int i = 0; i < NUM_BUFFERS && bSuccess; i++) { if (FAILED(err = g_ddInterface->CreateSurface(&captureDesc, &ddCaptures[i], NULL))) { logOutput << CurrentTimeString() << "SetupDDraw: Could not create offscreen capture" << endl; printDDrawError(err, "SetupDDraw"); bSuccess = false; break; } } ddrawSurfaceCreate.Rehook(); if (bSuccess) { bHasTextures = true; SetEvent(hSignalReady); OSInitializeTimer(); } } if (bSuccess) { logOutput << CurrentTimeString() << "SetupDDraw successfull" << endl; HookAll(); return true; } else { logOutput << CurrentTimeString() << "SetupDDraw failed" << endl; CleanUpDDraw(); return false; } }
void CleanUpDDraw() { logOutput << CurrentTimeString() << "Cleaning up" << endl; if (copyData) copyData->lastRendered = -1; if (hCopyThread) { bKillThread = true; SetEvent(hCopyEvent); if (WaitForSingleObject(hCopyThread, 500) != WAIT_OBJECT_0) TerminateThread(hCopyThread, -1); CloseHandle(hCopyThread); CloseHandle(hCopyEvent); hCopyThread = NULL; hCopyEvent = NULL; } ddrawSurfaceRelease.Unhook(); for (int i = 0; i < NUM_BUFFERS; i++) { if (ddCaptures[i]) { ddCaptures[i]->Release(); ddCaptures[i] = NULL; } } ddrawSurfaceRelease.Rehook(); DestroySharedMemory(); bHasTextures = false; curCapture = 0; curCPUTexture = 0; keepAliveTime = 0; resetCount++; copyWait = 0; lastTime = 0; g_frontSurface = NULL; g_bUseFlipMethod = false; bTargetAcquired = false; g_dwSize = 0; g_bUse32bitCapture = false; g_bConvert16to32 = false; g_bUsePalette = false; g_dwCaptureSize = 0; if (g_ddInterface) { g_ddInterface->Release(); g_ddInterface = NULL; } g_CurrentPalette.Free(); if (g_surfaceDesc) delete g_surfaceDesc; g_surfaceDesc = NULL; if (ddUnlockFctMutex) { CloseHandle(ddUnlockFctMutex); ddUnlockFctMutex = 0; } //UnhookAll(); logOutput << CurrentTimeString() << "---------------------- Cleared DirectDraw Capture ----------------------" << endl; }
bool InitDDrawCapture() { bool versionSupported = false; HMODULE hDDrawLib = NULL; if (hDDrawLib = GetModuleHandle(TEXT("ddraw.dll"))) { bool isWinVistaMin = IsWindowsVistaOrGreater(); bool isWin7min = IsWindows7OrGreater(); bool isWin8min = IsWindows8OrGreater(); UPARAM libBaseAddr = UPARAM(hDDrawLib); UPARAM surfCreateOffset; UPARAM surfUnlockOffset; UPARAM surfReleaseOffset; UPARAM surfRestoreOffset; UPARAM surfBltOffset; UPARAM surfFlipOffset; UPARAM surfSetPaletteOffset; UPARAM palSetEntriesOffset; if (isWinVistaMin) { if (!isWin7min) { RUNEVERYRESET logOutput << CurrentTimeString() << "Windows Vista not supported yet" << endl; } else if (isWin7min && !isWin8min) { surfCreateOffset = 0x617E; surfUnlockOffset = 0x4C40; surfReleaseOffset = 0x3239; surfRestoreOffset = 0x3E9CB; surfBltOffset = surfCreateOffset + 0x44F63; surfFlipOffset = surfCreateOffset + 0x37789; surfSetPaletteOffset = surfCreateOffset + 0x4D2D3; palSetEntriesOffset = surfCreateOffset + 0x4CE68; versionSupported = true; } else if (isWin8min) { surfCreateOffset = 0x9530 + 0xC00; surfUnlockOffset = surfCreateOffset + 0x2A1D0; surfReleaseOffset = surfCreateOffset - 0x1A80; surfRestoreOffset = surfCreateOffset + 0x36000; surfBltOffset = surfCreateOffset + 0x438DC; surfFlipOffset = surfCreateOffset + 0x33EF3; surfSetPaletteOffset = surfCreateOffset + 0x4D3B8; palSetEntriesOffset = surfCreateOffset + 0x4CF4C; versionSupported = false; // some crash bugs remaining RUNEVERYRESET logOutput << CurrentTimeString() << "Windows 8 not supported yet" << endl; } else { RUNEVERYRESET logOutput << CurrentTimeString() << "Unknown OS version" << endl; } } else { RUNEVERYRESET logOutput << CurrentTimeString() << "OS version not supported" << endl; } if (versionSupported) { ddrawSurfaceCreate.Hook((FARPROC)(libBaseAddr + surfCreateOffset), (FARPROC)CreateSurface); ddrawSurfaceRestore.Hook((FARPROC)(libBaseAddr + surfRestoreOffset), (FARPROC)Restore); ddrawSurfaceRelease.Hook((FARPROC)(libBaseAddr + surfReleaseOffset), (FARPROC)Release); ddrawSurfaceUnlock.Hook((FARPROC)(libBaseAddr + surfUnlockOffset), (FARPROC)Unlock); ddrawSurfaceBlt.Hook((FARPROC)(libBaseAddr + surfBltOffset), (FARPROC)Blt); ddrawSurfaceFlip.Hook((FARPROC)(libBaseAddr + surfFlipOffset), (FARPROC)Flip); ddrawSurfaceSetPalette.Hook((FARPROC)(libBaseAddr + surfSetPaletteOffset), (FARPROC)SetPalette); ddrawPaletteSetEntries.Hook((FARPROC)(libBaseAddr + palSetEntriesOffset), (FARPROC)PaletteSetEntries); ddrawSurfaceUnlock.Rehook(); ddrawSurfaceFlip.Rehook(); ddrawSurfaceBlt.Rehook(); /* ddrawSurfaceCreate.Rehook(); ddrawSurfaceRestore.Rehook(); ddrawSurfaceRelease.Rehook(); ddrawSurfaceSetPalette.Rehook(); ddrawPaletteSetEntries.Rehook(); */ } } return versionSupported; }
bool InitGLCapture() { bool bSuccess = false; HMODULE hGL = GetModuleHandle(TEXT("opengl32.dll")); if(hGL) { pglReadBuffer = (GLREADBUFFERPROC) GetProcAddress(hGL, "glReadBuffer"); pglReadPixels = (GLREADPIXELSPROC) GetProcAddress(hGL, "glReadPixels"); pglGetError = (GLGETERRORPROC) GetProcAddress(hGL, "glGetError"); pwglSwapLayerBuffers= (WGLSWAPLAYERBUFFERSPROC) GetProcAddress(hGL, "wglSwapLayerBuffers"); pwglDeleteContext = (WGLDELETECONTEXTPROC) GetProcAddress(hGL, "wglDeleteContext"); pwglGetProcAddress = (WGLGETPROCADDRESSPROC) GetProcAddress(hGL, "wglGetProcAddress"); pwglMakeCurrent = (WGLMAKECURRENTPROC) GetProcAddress(hGL, "wglMakeCurrent"); pwglCreateContext = (WGLCREATECONTEXTPROC) GetProcAddress(hGL, "wglCreateContext"); if( !pglReadBuffer || !pglReadPixels || !pglGetError || !pwglSwapLayerBuffers || !pwglDeleteContext || !pwglGetProcAddress || !pwglMakeCurrent || !pwglCreateContext) { return false; } HDC hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL); if(hDC) { PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 32; pfd.cAccumBits = 32; pfd.iLayerType = PFD_MAIN_PLANE; SetPixelFormat(hDC, ChoosePixelFormat(hDC, &pfd), &pfd); HGLRC hGlrc = jimglCreateContext(hDC); if(hGlrc) { jimglMakeCurrent(hDC, hGlrc); pglBufferData = (GLBUFFERDATAARBPROC) jimglGetProcAddress("glBufferData"); pglDeleteBuffers = (GLDELETEBUFFERSARBPROC) jimglGetProcAddress("glDeleteBuffers"); pglGenBuffers = (GLGENBUFFERSARBPROC) jimglGetProcAddress("glGenBuffers"); pglMapBuffer = (GLMAPBUFFERPROC) jimglGetProcAddress("glMapBuffer"); pglUnmapBuffer = (GLUNMAPBUFFERPROC) jimglGetProcAddress("glUnmapBuffer"); pglBindBuffer = (GLBINDBUFFERPROC) jimglGetProcAddress("glBindBuffer"); UINT lastErr = GetLastError(); if(pglBufferData && pglDeleteBuffers && pglGenBuffers && pglMapBuffer && pglUnmapBuffer && pglBindBuffer) { glHookSwapBuffers.Hook((FARPROC)SwapBuffers, (FARPROC)SwapBuffersHook); glHookSwapLayerBuffers.Hook((FARPROC)jimglSwapLayerBuffers, (FARPROC)wglSwapLayerBuffersHook); glHookDeleteContext.Hook((FARPROC)jimglDeleteContext, (FARPROC)wglDeleteContextHook); bSuccess = true; } jimglMakeCurrent(NULL, NULL); jimglDeleteContext(hGlrc); if(bSuccess) { glHookSwapBuffers.Rehook(); glHookSwapLayerBuffers.Rehook(); glHookDeleteContext.Rehook(); } } DeleteDC(hDC); } } return bSuccess; }
bool InitGLCapture() { static HWND hwndOpenGLSetupWindow = NULL; bool bSuccess = false; if(!hwndOpenGLSetupWindow) { WNDCLASSEX windowClass; ZeroMemory(&windowClass, sizeof(windowClass)); windowClass.cbSize = sizeof(windowClass); windowClass.style = CS_OWNDC; windowClass.lpfnWndProc = DefWindowProc; windowClass.lpszClassName = TEXT("OBSOGLHookClass"); windowClass.hInstance = hinstMain; if(RegisterClassEx(&windowClass)) { hwndOpenGLSetupWindow = CreateWindowEx (0, TEXT("OBSOGLHookClass"), TEXT("OBS OpenGL Context Window"), WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 1, 1, NULL, NULL, hinstMain, NULL ); } } HMODULE hGL = GetModuleHandle(TEXT("opengl32.dll")); if(hGL && hwndOpenGLSetupWindow) { pglReadBuffer = (GLREADBUFFERPROC) GetProcAddress(hGL, "glReadBuffer"); pglReadPixels = (GLREADPIXELSPROC) GetProcAddress(hGL, "glReadPixels"); pglGetError = (GLGETERRORPROC) GetProcAddress(hGL, "glGetError"); pwglSwapLayerBuffers= (WGLSWAPLAYERBUFFERSPROC) GetProcAddress(hGL, "wglSwapLayerBuffers"); pwglSwapBuffers= (WGLSWAPBUFFERSPROC) GetProcAddress(hGL, "wglSwapBuffers"); pwglDeleteContext = (WGLDELETECONTEXTPROC) GetProcAddress(hGL, "wglDeleteContext"); pwglGetProcAddress = (WGLGETPROCADDRESSPROC) GetProcAddress(hGL, "wglGetProcAddress"); pwglMakeCurrent = (WGLMAKECURRENTPROC) GetProcAddress(hGL, "wglMakeCurrent"); pwglCreateContext = (WGLCREATECONTEXTPROC) GetProcAddress(hGL, "wglCreateContext"); if( !pglReadBuffer || !pglReadPixels || !pglGetError || !pwglSwapLayerBuffers || !pwglSwapBuffers || !pwglDeleteContext || !pwglGetProcAddress || !pwglMakeCurrent || !pwglCreateContext) { return false; } HDC hDC = GetDC(hwndOpenGLSetupWindow); if(hDC) { PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_GENERIC_ACCELERATED; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 32; pfd.cAccumBits = 32; pfd.iLayerType = PFD_MAIN_PLANE; SetPixelFormat(hDC, ChoosePixelFormat(hDC, &pfd), &pfd); HGLRC hGlrc = jimglCreateContext(hDC); if(hGlrc) { jimglMakeCurrent(hDC, hGlrc); pglBufferData = (GLBUFFERDATAARBPROC) jimglGetProcAddress("glBufferData"); pglDeleteBuffers = (GLDELETEBUFFERSARBPROC) jimglGetProcAddress("glDeleteBuffers"); pglGenBuffers = (GLGENBUFFERSARBPROC) jimglGetProcAddress("glGenBuffers"); pglMapBuffer = (GLMAPBUFFERPROC) jimglGetProcAddress("glMapBuffer"); pglUnmapBuffer = (GLUNMAPBUFFERPROC) jimglGetProcAddress("glUnmapBuffer"); pglBindBuffer = (GLBINDBUFFERPROC) jimglGetProcAddress("glBindBuffer"); UINT lastErr = GetLastError(); if(pglBufferData && pglDeleteBuffers && pglGenBuffers && pglMapBuffer && pglUnmapBuffer && pglBindBuffer) { glHookSwapBuffers.Hook((FARPROC)SwapBuffers, (FARPROC)SwapBuffersHook); glHookSwapLayerBuffers.Hook((FARPROC)jimglSwapLayerBuffers, (FARPROC)wglSwapLayerBuffersHook); glHookwglSwapBuffers.Hook((FARPROC)jimglSwapBuffers, (FARPROC)wglSwapBuffersHook); glHookDeleteContext.Hook((FARPROC)jimglDeleteContext, (FARPROC)wglDeleteContextHook); bSuccess = true; } jimglMakeCurrent(NULL, NULL); jimglDeleteContext(hGlrc); ReleaseDC(hwndOpenGLSetupWindow, hDC); if(bSuccess) { glHookSwapBuffers.Rehook(); glHookSwapLayerBuffers.Rehook(); glHookwglSwapBuffers.Rehook(); glHookDeleteContext.Rehook(); DestroyWindow(hwndOpenGLSetupWindow); hwndOpenGLSetupWindow = NULL; UnregisterClass(TEXT("OBSOGLHookClass"), hinstMain); } } if(hwndOpenGLSetupWindow) ReleaseDC(hwndOpenGLSetupWindow, hDC); } } return bSuccess; }
HRESULT STDMETHODCALLTYPE SwapResizeBuffersHook(UINT bufferCount, UINT width, UINT height, DXGI_FORMAT giFormat, UINT flags) { IDXGISwapChain *swap = (IDXGISwapChain*)this; gi11swapResizeBuffers.Unhook(); HRESULT hRes = swap->ResizeBuffers(bufferCount, width, height, giFormat, flags); gi11swapResizeBuffers.Rehook(); if(lpCurrentSwap == NULL && !bTargetAcquired) { lpCurrentSwap = swap; bTargetAcquired = true; } if(lpCurrentSwap == swap) SetupD3D11(swap); return hRes; }