void SetupD3D101(IDXGISwapChain *swapChain) { logOutput << CurrentTimeString() << "setting up d3d10.1 data" << endl; ClearD3D101Data(); DXGI_SWAP_CHAIN_DESC scd; if(SUCCEEDED(swapChain->GetDesc(&scd))) { d3d101CaptureInfo.format = ConvertGIBackBufferFormat(scd.BufferDesc.Format); if(d3d101CaptureInfo.format != GS_UNKNOWNFORMAT) { if( dxgiFormat != scd.BufferDesc.Format || d3d101CaptureInfo.cx != scd.BufferDesc.Width || d3d101CaptureInfo.cy != scd.BufferDesc.Height || d3d101CaptureInfo.hwndCapture != (DWORD)scd.OutputWindow) { dxgiFormat = FixCopyTextureFormat(scd.BufferDesc.Format); d3d101CaptureInfo.cx = scd.BufferDesc.Width; d3d101CaptureInfo.cy = scd.BufferDesc.Height; d3d101CaptureInfo.hwndCapture = (DWORD)scd.OutputWindow; bIsMultisampled = scd.SampleDesc.Count > 1; logOutput << CurrentTimeString() << "found dxgi format (dx10.1) of: " << UINT(dxgiFormat) << ", size: {" << scd.BufferDesc.Width << ", " << scd.BufferDesc.Height << "}, multisampled: " << (bIsMultisampled ? "true" : "false") << endl; } } } lastTime = 0; OSInitializeTimer(); }
inline bool AttemptToHookSomething() { bool bFoundSomethingToHook = false; if(!bD3D9Hooked && InitD3D9Capture()) { logOutput << CurrentTimeString() << "D3D9 Present" << endl; bFoundSomethingToHook = true; bD3D9Hooked = true; } if(!bDXGIHooked && InitDXGICapture()) { logOutput << CurrentTimeString() << "DXGI Present" << endl; bFoundSomethingToHook = true; bDXGIHooked = true; } if(!bGLHooked && InitGLCapture()) { logOutput << CurrentTimeString() << "GL Present" << endl; bFoundSomethingToHook = true; bGLHooked = true; } /* if(!bDirectDrawHooked && InitDDrawCapture()) { OutputDebugString(TEXT("DirectDraw Present\r\n")); bFoundSomethingToHook = true; bDirectDrawfHooked = true; }*/ return bFoundSomethingToHook; }
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 DoD3D101Hook(ID3D10Device *device) { HRESULT hErr; D3D10_TEXTURE2D_DESC texGameDesc; ZeroMemory(&texGameDesc, sizeof(texGameDesc)); texGameDesc.Width = d3d101CaptureInfo.cx; texGameDesc.Height = d3d101CaptureInfo.cy; texGameDesc.MipLevels = 1; texGameDesc.ArraySize = 1; texGameDesc.Format = dxgiFormat; texGameDesc.SampleDesc.Count = 1; texGameDesc.BindFlags = D3D10_BIND_RENDER_TARGET|D3D10_BIND_SHADER_RESOURCE; texGameDesc.Usage = D3D10_USAGE_DEFAULT; texGameDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED; ID3D10Texture2D *d3d101Tex; if(FAILED(hErr = device->CreateTexture2D(&texGameDesc, NULL, &d3d101Tex))) { RUNEVERYRESET logOutput << CurrentTimeString() << "DoD3D101Hook: failed to create intermediary texture, result = " << UINT(hErr) << endl; return false; } if(FAILED(hErr = d3d101Tex->QueryInterface(__uuidof(ID3D10Resource), (void**)©D3D101TextureGame))) { RUNEVERYRESET logOutput << CurrentTimeString() << "DoD3D101Hook: d3d101Tex->QueryInterface(ID3D10Resource) failed, result = " << UINT(hErr) << endl; d3d101Tex->Release(); return false; } IDXGIResource *res; if(FAILED(hErr = d3d101Tex->QueryInterface(IID_IDXGIResource, (void**)&res))) { RUNEVERYRESET logOutput << CurrentTimeString() << "DoD3D101Hook: d3d101Tex->QueryInterface(IDXGIResource) failed, result = " << UINT(hErr) << endl; d3d101Tex->Release(); return false; } if(FAILED(res->GetSharedHandle(&sharedHandle))) { RUNEVERYRESET logOutput << CurrentTimeString() << "DoD3D101Hook: res->GetSharedHandle failed, result = " << UINT(hErr) << endl; d3d101Tex->Release(); res->Release(); return false; } d3d101Tex->Release(); res->Release(); return true; }
void Free() { bool bWait = true; // try locking mutexes so we don't accidently free memory used by copythread HANDLE mutexes[2]; for (int i = 0; i < 2; i++) { if (!DuplicateHandle(GetCurrentProcess(), textureMutexes[i], GetCurrentProcess(), &mutexes[i], NULL, FALSE, DUPLICATE_SAME_ACCESS)) { logOutput << CurrentTimeString() << "Palette::Free(): could not duplicate textureMutex handles, assuming OBS was closed and copy thread finished" << endl; bWait = false; break; } } // wait 2 seconds before deleting memory DWORD ret = WaitForMultipleObjects(2, mutexes, TRUE, 2000); destroy(); if (bWait) { if (ret == WAIT_OBJECT_0) { ReleaseMutex(mutexes[0]); ReleaseMutex(mutexes[1]); } CloseHandle(mutexes[0]); CloseHandle(mutexes[1]); } }
void LogPresentParams(D3DPRESENT_PARAMETERS &pp) { string strTime = CurrentTimeString(); /*if (pp.hDeviceWindow) { UINT testLen = GetWindowTextLength(pp.hDeviceWindow); testLen++; string strName; strName.resize(testLen); GetWindowTextA(pp.hDeviceWindow, (char*)strName.c_str(), testLen); logOutput << CurrentTimeString() << "found d3d9 present params for window: " << strName << endl; }*/ logOutput << strTime << "D3DPRESENT_PARAMETERS {" << endl; logOutput << strTime << "\t" "BackBufferWidth: " << pp.BackBufferWidth << endl; logOutput << strTime << "\t" "BackBufferHeight: " << pp.BackBufferHeight << endl; logOutput << strTime << "\t" "BackBufferFormat: " << GetD3D9FormatName(pp.BackBufferFormat) << endl; logOutput << strTime << "\t" "BackBufferCount: " << pp.BackBufferCount << endl; logOutput << strTime << "\t" "MultiSampleType: " << GetD3D9MultiSampleTypeName(pp.MultiSampleType) << endl; logOutput << strTime << "\t" "MultiSampleQuality: " << pp.MultiSampleQuality << endl; logOutput << strTime << "\t" "SwapEffect: " << GetD3D9SwapEffectName(pp.SwapEffect) << endl; logOutput << strTime << "\t" "hDeviceWindow: " << DWORD(pp.hDeviceWindow) << endl; logOutput << strTime << "\t" "Windowed: " << (pp.Windowed ? "true" : "false") << endl; logOutput << strTime << "\t" "EnableAutoDepthStencil: " << (pp.EnableAutoDepthStencil ? "true" : "false") << endl; logOutput << strTime << "\t" "AutoDepthStencilFormat: " << GetD3D9FormatName(pp.AutoDepthStencilFormat) << endl; logOutput << strTime << "\t" "Flags: " << GetD3D9D3DPPFlagsString(pp.Flags) << endl; logOutput << strTime << "\t" "FullScreen_RefreshRateInHz: " << pp.FullScreen_RefreshRateInHz << endl; logOutput << strTime << "\t" "PresentationInterval: " << pp.PresentationInterval << endl; logOutput << strTime << "};" << endl; }
inline bool AttemptToHookSomething() { if (!hwndSender || !hwndD3DDummyWindow || !hwndOpenGLSetupWindow) return false; bool bFoundSomethingToHook = false; if(!bD3D9Hooked) { if (InitD3D9Capture()) { logOutput << CurrentTimeString() << "D3D9 Present" << endl; bFoundSomethingToHook = true; bD3D9Hooked = true; } } else { //occasionally, certain applications can reset the d3d9 hook, or clear it, or something. //so, we forcibly make sure that the d3d9 function is still hooked. CheckD3D9Capture(); } if(!bDXGIHooked && InitDXGICapture()) { logOutput << CurrentTimeString() << "DXGI Present" << endl; bFoundSomethingToHook = true; bDXGIHooked = true; } if(!bGLHooked && InitGLCapture()) { logOutput << CurrentTimeString() << "GL Present" << endl; bFoundSomethingToHook = true; bGLHooked = true; } else { CheckGLCapture(); } /* if(!bDirectDrawHooked && InitDDrawCapture()) { OutputDebugString(TEXT("DirectDraw Present\r\n")); bFoundSomethingToHook = true; bDirectDrawfHooked = true; }*/ return bFoundSomethingToHook; }
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; } }
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; }
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(); }
void ClearD3D101Data() { bHasTextures = false; texData = NULL; sharedHandle = NULL; SafeRelease(copyD3D101TextureGame); DestroySharedMemory(); keepAliveTime = 0; resetCount++; logOutput << CurrentTimeString() << "---------------------- Cleared D3D10.1 Capture ----------------------" << endl; }
DWORD CopyGLCPUTextureThread(LPVOID lpUseless) { int sharedMemID = 0; HANDLE hEvent = NULL; if(!DuplicateHandle(GetCurrentProcess(), hCopyEvent, GetCurrentProcess(), &hEvent, NULL, FALSE, DUPLICATE_SAME_ACCESS)) { logOutput << CurrentTimeString() << "CopyGLCPUTextureThread: couldn't duplicate handle" << endl; return 0; } while(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) { if(bKillThread) break; int nextSharedMemID = sharedMemID == 0 ? 1 : 0; DWORD copyTex = curCPUTexture; LPVOID data = pCopyData; if(copyTex < NUM_BUFFERS && data != NULL) { OSEnterMutex(glDataMutexes[copyTex]); int lastRendered = -1; //copy to whichever is available if(WaitForSingleObject(textureMutexes[sharedMemID], 0) == WAIT_OBJECT_0) lastRendered = (int)sharedMemID; else if(WaitForSingleObject(textureMutexes[nextSharedMemID], 0) == WAIT_OBJECT_0) lastRendered = (int)nextSharedMemID; if(lastRendered != -1) { memcpy(textureBuffers[lastRendered], data, glcaptureInfo.pitch*glcaptureInfo.cy); ReleaseMutex(textureMutexes[lastRendered]); copyData->lastRendered = (UINT)lastRendered; } OSLeaveMutex(glDataMutexes[copyTex]); } sharedMemID = nextSharedMemID; } CloseHandle(hEvent); return 0; }
void __cdecl Logva(const TCHAR *format, va_list argptr) { if(!format) return; String strCurTime = CurrentTimeString(); strCurTime << TEXT(": "); String strOut = strCurTime; strOut << FormattedStringva(format, argptr); strOut.FindReplace(TEXT("\n"), String() << TEXT("\n") << strCurTime); OpenLogFile(); LogFile.WriteAsUTF8(strOut, strOut.Length()); LogFile.WriteAsUTF8(TEXT("\r\n")); CloseLogFile(); }
void LogD3D9SurfaceInfo(IDirect3DSurface9 *surf) { if (!surf) return; string strTime = CurrentTimeString(); D3DSURFACE_DESC sd; ZeroMemory(&sd, sizeof(sd)); if (SUCCEEDED(surf->GetDesc(&sd))) { logOutput << strTime << "D3DSURFACE_DESC {" << endl; logOutput << strTime << "\t" "Format: " << GetD3D9FormatName(sd.Format) << endl; logOutput << strTime << "\t" "Type: " << GetD3D9ResourceTypeName(sd.Type) << endl; logOutput << strTime << "\t" "Usage: " << GetD3D9UsageString(sd.Usage) << endl; logOutput << strTime << "\t" "Pool: " << GetD3D9PoolName(sd.Pool) << endl; logOutput << strTime << "\t" "MultiSampleType: " << GetD3D9MultiSampleTypeName(sd.MultiSampleType) << endl; logOutput << strTime << "\t" "MultiSampleQuality: " << sd.MultiSampleQuality << endl; logOutput << strTime << "\t" "Width: " << sd.Width << endl; logOutput << strTime << "\t" "Height: " << sd.Height << endl; logOutput << strTime << "};" << endl; } else { logOutput << strTime << "could not get D3DSURFACE_DESC from backbuffer for some reason" << endl; } }
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; }
DWORD WINAPI CaptureThread(HANDLE hDllMainThread) { bool bSuccess = false; //wait for dll initialization to finish before executing any initialization code if(hDllMainThread) { WaitForSingleObject(hDllMainThread, INFINITE); CloseHandle(hDllMainThread); } TCHAR lpLogPath[MAX_PATH]; SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, lpLogPath); wcscat_s(lpLogPath, MAX_PATH, TEXT("\\OBS\\pluginData\\captureHookLog.txt")); dummyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if(!logOutput.is_open()) logOutput.open(lpLogPath, ios_base::in | ios_base::out | ios_base::trunc, _SH_DENYNO); wstringstream str; str << OBS_KEEPALIVE_EVENT << UINT(GetCurrentProcessId()); strKeepAlive = str.str(); logOutput << CurrentDateTimeString() << "we're booting up: " << endl; InitializeCriticalSection(&d3d9EndMutex); InitializeCriticalSection(&glMutex); WNDCLASS wc; ZeroMemory(&wc, sizeof(wc)); wc.hInstance = hinstMain; wc.lpszClassName = SENDER_WINDOWCLASS; wc.lpfnWndProc = (WNDPROC)DefWindowProc; DWORD procID = GetCurrentProcessId(); wstringstream strRestartEvent, strEndEvent, strReadyEvent, strExitEvent, strInfoMemory; strRestartEvent << RESTART_CAPTURE_EVENT << procID; strEndEvent << END_CAPTURE_EVENT << procID; strReadyEvent << CAPTURE_READY_EVENT << procID; strExitEvent << APP_EXIT_EVENT << procID; strInfoMemory << INFO_MEMORY << procID; hSignalRestart = GetEvent(strRestartEvent.str().c_str()); hSignalEnd = GetEvent(strEndEvent.str().c_str()); hSignalReady = GetEvent(strReadyEvent.str().c_str()); hSignalExit = GetEvent(strExitEvent.str().c_str()); hInfoFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(CaptureInfo), strInfoMemory.str().c_str()); if(!hInfoFileMap) { logOutput << CurrentTimeString() << "CaptureThread: could not info file mapping" << endl; return 0; } infoMem = (CaptureInfo*)MapViewOfFile(hInfoFileMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CaptureInfo)); if(!infoMem) { logOutput << CurrentTimeString() << "CaptureThread: could not map view of info shared memory" << endl; CloseHandle(hInfoFileMap); hInfoFileMap = NULL; return 0; } hwndOBS = FindWindow(OBS_WINDOW_CLASS, NULL); if(!hwndOBS) { logOutput << CurrentTimeString() << "CaptureThread: could not find main application window? wtf? seriously?" << endl; return 0; } if (RegisterClass(&wc)) { hwndSender = CreateWindow(SENDER_WINDOWCLASS, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinstMain, 0); if (hwndSender) { textureMutexes[0] = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXTURE_MUTEX1); if (textureMutexes[0]) { textureMutexes[1] = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXTURE_MUTEX2); if (textureMutexes[1]) { while(!AttemptToHookSomething()) Sleep(50); logOutput << CurrentTimeString() << "(half life scientist) everything.. seems to be in order" << endl; MSG msg; while (MsgWaitForMultipleObjects(1, &dummyEvent, FALSE, 3000, QS_ALLINPUT) != WAIT_ABANDONED_0) { //while (GetMessageTimeout(msg, 3000)) { AttemptToHookSomething(); while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } CloseHandle(textureMutexes[1]); textureMutexes[1] = NULL; } else { logOutput << CurrentTimeString() << "could not open texture mutex 2" << endl; } CloseHandle(textureMutexes[0]); textureMutexes[0] = NULL; } else { logOutput << CurrentTimeString() << "could not open texture mutex 1" << endl; } DestroyWindow(hwndSender); } else { logOutput << CurrentTimeString() << "could not create sender window" << endl; } } logOutput << CurrentTimeString() << "WARNING: exit out of the main thread loop somehow" << endl; return 0; }
DWORD WINAPI CaptureThread(HANDLE hDllMainThread) { bool bSuccess = false; //wait for dll initialization to finish before executing any initialization code if(hDllMainThread) { WaitForSingleObject(hDllMainThread, INFINITE); CloseHandle(hDllMainThread); } TCHAR lpLogPath[MAX_PATH]; SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, lpLogPath); wcscat_s(lpLogPath, MAX_PATH, TEXT("\\OBS\\pluginData\\captureHookLog.txt")); dummyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if(!logOutput.is_open()) logOutput.open(lpLogPath, ios_base::in | ios_base::out | ios_base::trunc, _SH_DENYNO); wstringstream str; str << OBS_KEEPALIVE_EVENT << UINT(GetCurrentProcessId()); strKeepAlive = str.str(); logOutput << CurrentDateTimeString() << "we're booting up: " << endl; InitializeCriticalSection(&d3d9EndMutex); InitializeCriticalSection(&glMutex); DWORD procID = GetCurrentProcessId(); wstringstream strRestartEvent, strEndEvent, strReadyEvent, strExitEvent, strInfoMemory; strRestartEvent << RESTART_CAPTURE_EVENT << procID; strEndEvent << END_CAPTURE_EVENT << procID; strReadyEvent << CAPTURE_READY_EVENT << procID; strExitEvent << APP_EXIT_EVENT << procID; strInfoMemory << INFO_MEMORY << procID; hSignalRestart = GetEvent(strRestartEvent.str().c_str()); hSignalEnd = GetEvent(strEndEvent.str().c_str()); hSignalReady = GetEvent(strReadyEvent.str().c_str()); hSignalExit = GetEvent(strExitEvent.str().c_str()); DWORD bla; HANDLE hWindowThread = CreateThread(NULL, 0, DummyWindowThread, NULL, 0, &bla); if (!hWindowThread) { logOutput << CurrentTimeString() << "CaptureThread: could not create window thread for some reason" << endl; return 0; } CloseHandle(hWindowThread); hInfoFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(CaptureInfo), strInfoMemory.str().c_str()); if(!hInfoFileMap) { logOutput << CurrentTimeString() << "CaptureThread: could not info file mapping" << endl; return 0; } infoMem = (CaptureInfo*)MapViewOfFile(hInfoFileMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CaptureInfo)); if(!infoMem) { logOutput << CurrentTimeString() << "CaptureThread: could not map view of info shared memory" << endl; CloseHandle(hInfoFileMap); hInfoFileMap = NULL; return 0; } hwndOBS = FindWindow(OBS_WINDOW_CLASS, NULL); if(!hwndOBS) { logOutput << CurrentTimeString() << "CaptureThread: could not find main application window? wtf? seriously?" << endl; return 0; } textureMutexes[0] = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXTURE_MUTEX1); if (textureMutexes[0]) { textureMutexes[1] = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXTURE_MUTEX2); if (textureMutexes[1]) { while(!AttemptToHookSomething()) Sleep(50); logOutput << CurrentTimeString() << "(half life scientist) everything.. seems to be in order" << endl; while (1) { AttemptToHookSomething(); Sleep(4000); } CloseHandle(textureMutexes[1]); textureMutexes[1] = NULL; } else { logOutput << CurrentTimeString() << "could not open texture mutex 2" << endl; } CloseHandle(textureMutexes[0]); textureMutexes[0] = NULL; } else { logOutput << CurrentTimeString() << "could not open texture mutex 1" << endl; } logOutput << CurrentTimeString() << "WARNING: exit out of the main thread loop somehow" << endl; return 0; }
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(); } } } }
KString KString::CurrentDateTimeString() { return DateTimeString(CurrentDateString(), CurrentTimeString()); }
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); }
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; }
void printDDrawError(HRESULT err, const char* callerName = "") { if (err == DD_OK) return; std::string s; switch (err) { case DDERR_CANTCREATEDC: s = "can't create dc"; break; case DDERR_CANTLOCKSURFACE: s = "can't lock surface"; break; case DDERR_CLIPPERISUSINGHWND: s = "clipper is using hwnd"; break; case DDERR_COLORKEYNOTSET: s = "color key not set"; break; case DDERR_CURRENTLYNOTAVAIL: s = "currently not available"; break; case DDERR_DCALREADYCREATED: s = "dc already created"; break; case DDERR_DEVICEDOESNTOWNSURFACE: s = "device does not own surface"; break; case DDERR_DIRECTDRAWALREADYCREATED: s = "direct draw already created"; break; case DDERR_EXCLUSIVEMODEALREADYSET: s = "exclusive mode already set"; break; case DDERR_GENERIC: s = "undefined error"; break; case DDERR_HEIGHTALIGN: s = "height alignment is not a multiple of required alignment"; break; case DDERR_IMPLICITLYCREATED: s = "cannot restore surface, implicitly created"; break; case DDERR_INCOMPATIBLEPRIMARY: s = "incompatible primary"; break; case DDERR_INVALIDCAPS: s = "invalid caps"; break; case DDERR_INVALIDCLIPLIST: s = "invalid cliplist"; break; case DDERR_INVALIDMODE: s = "invalid mode"; break; case DDERR_INVALIDOBJECT: s = "invalid object"; break; case DDERR_INVALIDPARAMS: s = "invalid params"; break; case DDERR_INVALIDPIXELFORMAT: s = "invalid pixel format"; break; case DDERR_INVALIDPOSITION: s = "invalid position"; break; case DDERR_INVALIDRECT: s = "invalid rect"; break; case DDERR_LOCKEDSURFACES: s = "surface(s) locked"; break; case DDERR_MOREDATA: s = "data size exceeds buffer size"; break; case DDERR_NOALPHAHW: s = "no alpha acceleration hw available"; break; case DDERR_NOBLTHW: s = "no hw blit available"; break; case DDERR_NOCLIPLIST: s = "no cliplist available"; break; case DDERR_NOCLIPPERATTACHED: s = "no clipper attached"; break; case DDERR_NOCOLORCONVHW: s = "no color conversion hw available"; break; case DDERR_NOCOLORKEYHW: s = "no hw support for dest color key"; break; case DDERR_NOCOOPERATIVELEVELSET: s = "no cooperative level set"; break; case DDERR_NODC: s = "no dc available"; break; case DDERR_NOEXCLUSIVEMODE: s = "application does not have exclusive mode"; break; case DDERR_NOFLIPHW: s = "no hw flip available"; break; case DDERR_NOOVERLAYDEST: s = "GetOverlayPosition() is called but UpdateOverlay() has not been called"; break; case DDERR_NOOVERLAYHW: s = "no hw overlay available"; break; case DDERR_NOPALETTEATTACHED: s = "no palette attached"; break; case DDERR_NORASTEROPHW: s = "no raster operation hw available"; break; case DDERR_NOSTRETCHHW: s = "no hw support for stretching available"; break; case DDERR_NOTAOVERLAYSURFACE: s = "not an overlay component"; break; case DDERR_NOTFLIPPABLE: s = "surface not flippable"; break; case DDERR_NOTFOUND: s = "item not found"; break; case DDERR_NOTLOCKED: s = "surface not locked"; break; case DDERR_NOTPALETTIZED: s = "surface is not palette-based"; break; case DDERR_NOVSYNCHW: s = "no vsync hw available"; break; case DDERR_NOZOVERLAYHW: s = "not supported (NOZOVERLAYHW)"; break; case DDERR_OUTOFCAPS: s = "hw needed has already been allocated"; break; case DDERR_OUTOFMEMORY: s = "out of memory"; break; case DDERR_OUTOFVIDEOMEMORY: s = "out of video memory"; break; case DDERR_OVERLAPPINGRECTS: s = "overlapping rects on surface"; break; case DDERR_OVERLAYNOTVISIBLE: s = "GetOverlayPosition() is called on a hidden overlay"; break; case DDERR_PALETTEBUSY: s = "palette is locked by another thread"; break; case DDERR_PRIMARYSURFACEALREADYEXISTS: s = "primary surface already exists"; break; case DDERR_REGIONTOOSMALL: s = "region too small"; break; case DDERR_SURFACEBUSY: s = "surface is locked by another thread"; break; case DDERR_SURFACELOST: s = "surface lost"; break; case DDERR_TOOBIGHEIGHT: s = "requested height too large"; break; case DDERR_TOOBIGSIZE: s = "requested size too large"; break; case DDERR_TOOBIGWIDTH: s = "requested width too large"; break; case DDERR_UNSUPPORTED: s = "operation unsupported"; break; case DDERR_UNSUPPORTEDFORMAT: s = "unsupported pixel format"; break; case DDERR_VERTICALBLANKINPROGRESS: s = "vertical blank in progress"; break; case DDERR_VIDEONOTACTIVE: s = "video port not active"; break; case DDERR_WASSTILLDRAWING: s = "blit operation incomplete"; break; case DDERR_WRONGMODE: s = "surface cannot be restored because it was created in a different mode"; break; default: logOutput << "unknown error: " << getCodeFromHRESULT(err) << endl; return; } std::stringstream msg; msg << CurrentTimeString() << callerName << " DDraw Error: " << s << "\n"; logOutput << msg.str(); }
// 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; } }
DWORD CopyDDrawTextureThread(LPVOID lpUseless) { int sharedMemID = 0; HANDLE hEvent = NULL; if (!DuplicateHandle(GetCurrentProcess(), hCopyEvent, GetCurrentProcess(), &hEvent, NULL, FALSE, DUPLICATE_SAME_ACCESS)) { logOutput << CurrentTimeString() << "CopyDDrawTextureThread: couldn't duplicate event handle - " << GetLastError() << endl; return 0; } std::stringstream msg; msg << CurrentTimeString() << "CopyDDrawTextureThread: waiting for copyEvents\n"; logOutput << msg.str(); msg.str(""); while (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) { //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: received copyEvent" << endl; if (bKillThread) break; int nextSharedMemID = sharedMemID == 0 ? 1 : 0; DWORD copyTex = curCPUTexture; if (copyTex < NUM_BUFFERS) { //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: processing data" << endl; int lastRendered = -1; //copy to whichever is available if (WaitForSingleObject(textureMutexes[sharedMemID], 0) == WAIT_OBJECT_0) lastRendered = (int)sharedMemID; else if (WaitForSingleObject(textureMutexes[nextSharedMemID], 0) == WAIT_OBJECT_0) lastRendered = (int)nextSharedMemID; if (lastRendered != -1) { //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: copying to memfile" << endl; HRESULT err; DDSURFACEDESC2 desc; desc.dwSize = sizeof(desc); DWORD flags = DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_NOSYSLOCK; //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: locking buffer" << endl; if (SUCCEEDED(err = ddCaptures[copyTex]->Lock(NULL, &desc, flags, NULL))) { //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: converting buffer" << endl; handleBufferConversion((LPDWORD)textureBuffers[lastRendered], (LPBYTE)desc.lpSurface, desc.lPitch); //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: unlocking buffer" << endl; if (FAILED(err = ddCaptures[copyTex]->Unlock(NULL))) { printDDrawError(err, "CopyDDrawTextureThread"); } /* else logOutput << CurrentTimeString() << "CopyDDrawTextureThread: done" << endl; */ //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: finished uploading" << endl; } else { RUNEVERYRESET logOutput << CurrentTimeString() << "CopyDDrawTextureThread: failed to lock capture surface" << endl; printDDrawError(err, "CopyDDrawTextureThread"); } ReleaseMutex(textureMutexes[lastRendered]); copyData->lastRendered = (UINT)lastRendered; } } sharedMemID = nextSharedMemID; //logOutput << CurrentTimeString() << "CopyDDrawTextureThread: waiting for event" << endl; } msg << CurrentTimeString() << "CopyDDrawTextureThread: killed\n"; logOutput << msg.str(); CloseHandle(hEvent); return 0; }
void DoGLCPUHook(RECT &rc) { glcaptureInfo.cx = rc.right; glcaptureInfo.cy = rc.bottom; glGenBuffers(NUM_BUFFERS, gltextures); DWORD dwSize = glcaptureInfo.cx*glcaptureInfo.cy*4; BOOL bSuccess = true; for(UINT i=0; i<NUM_BUFFERS; i++) { UINT test = 0; glBindBuffer(GL_PIXEL_PACK_BUFFER, gltextures[i]); glBufferData(GL_PIXEL_PACK_BUFFER, dwSize, 0, GL_STREAM_READ); if(!(glDataMutexes[i] = OSCreateMutex())) { logOutput << CurrentTimeString() << "DoGLCPUHook: OSCreateMutex " << i << " failed, GetLastError = " << GetLastError(); bSuccess = false; break; } } glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); if(bSuccess) { bKillThread = false; if(hCopyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CopyGLCPUTextureThread, NULL, 0, NULL)) { if(!(hCopyEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { logOutput << CurrentTimeString() << "DoGLCPUHook: CreateEvent failed, GetLastError = " << GetLastError(); bSuccess = false; } } else { logOutput << CurrentTimeString() << "DoGLCPUHook: CreateThread failed, GetLastError = " << GetLastError(); bSuccess = false; } } if(bSuccess) { glcaptureInfo.mapID = InitializeSharedMemoryCPUCapture(dwSize, &glcaptureInfo.mapSize, ©Data, textureBuffers); if(!glcaptureInfo.mapID) bSuccess = false; } if(bSuccess) { bHasTextures = true; glcaptureInfo.captureType = CAPTURETYPE_MEMORY; glcaptureInfo.hwndCapture = (DWORD)hwndTarget; glcaptureInfo.pitch = glcaptureInfo.cx*4; glcaptureInfo.bFlip = TRUE; memcpy(infoMem, &glcaptureInfo, sizeof(CaptureInfo)); SetEvent(hSignalReady); logOutput << CurrentTimeString() << "DoGLCPUHook: success" << endl; OSInitializeTimer(); } else ClearGLData(); }
bool SetupPalette(LPDIRECTDRAWPALETTE lpDDPalette) { if (!lpDDPalette) { //logOutput << CurrentTimeString() << "Detaching palette" << endl; g_CurrentPalette.Free(); g_bUsePalette = false; return false; } logOutput << CurrentTimeString() << "initializing palette" << endl; DWORD caps; HRESULT hr; if (FAILED(hr = lpDDPalette->GetCaps(&caps))) { logOutput << CurrentTimeString() << "Failed to get palette caps" << endl; printDDrawError(hr, "SetupPalette"); return false; } if (caps & DDPCAPS_8BITENTRIES) { logOutput << CurrentTimeString() << "8-bit index-palette used (lookup color is an index to another lookup table), not implemented" << endl; return false; } DWORD numEntries = 0; if (caps & DDPCAPS_8BIT) numEntries = 0x100; else if (caps & DDPCAPS_4BIT) numEntries = 0x10; else if (caps & DDPCAPS_2BIT) numEntries = 0x04; else if (caps & DDPCAPS_1BIT) numEntries = 0x02; else { logOutput << CurrentTimeString() << "Unrecognized palette format" << endl; return false; } //logOutput << CurrentTimeString() << "Trying to retrieve " << numEntries << " palette entries" << endl; g_CurrentPalette.Reallocate(numEntries); hr = lpDDPalette->GetEntries(0, 0, numEntries, g_CurrentPalette.entries); if (FAILED(hr)) { logOutput << CurrentTimeString() << "Failed to retrieve palette entries" << endl; printDDrawError(hr, "SetupPalette"); g_CurrentPalette.Free(); return false; } g_CurrentPalette.primary_surface_palette_ref = lpDDPalette; g_CurrentPalette.bInitialized = true; g_bUsePalette = true; logOutput << CurrentTimeString() << "Initialized palette with " << numEntries << " color entries" << endl; return true; }
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; }
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 ClearGLData() { 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; } for(int i=0; i<NUM_BUFFERS; i++) { if(glLockedTextures[i]) { OSEnterMutex(glDataMutexes[i]); glBindBuffer(GL_PIXEL_PACK_BUFFER, gltextures[i]); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glLockedTextures[i] = false; OSLeaveMutex(glDataMutexes[i]); } } if(bHasTextures) { glDeleteBuffers(NUM_BUFFERS, gltextures); bHasTextures = false; ZeroMemory(gltextures, sizeof(gltextures)); } for(int i=0; i<NUM_BUFFERS; i++) { if(glDataMutexes[i]) { OSCloseMutex(glDataMutexes[i]); glDataMutexes[i] = NULL; } } DestroySharedMemory(); copyData = NULL; copyWait = 0; lastTime = 0; curCapture = 0; curCPUTexture = 0; keepAliveTime = 0; resetCount++; pCopyData = NULL; logOutput << CurrentTimeString() << "---------------------- Cleared OpenGL Capture ----------------------" << endl; }