d3d9 抓取windows屏幕
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了d3d9 抓取windows屏幕相关的知识,希望对你有一定的参考价值。
抓取桌面的几种方式里面,有GDI,direct3d, win10 的DXGI ,等等
以下代码已经在gitee上,使用direct3d方式抓屏,保存png方式图片,可自行下载,代码里面还有一些抓取音频的,这些还没有整理,空了就整理这些代码
https://gitee.com/guanzhi0319/capture
#include <d3d9.h>
#pragma comment(lib,"d3d9.lib")
类声明
class ScreenCapture9
{
private:
//HWND _hwnd = NULL;
int _initbitmap = 0;
BITMAPINFO _bitmapinfo;
HDC _hMemDC = NULL;
HDC _hDC = NULL;
HBITMAP _hMemDCBitmap = NULL;
BYTE * _pPixel = NULL;
HCURSOR _hcur;
//vars
IDirect3D9* g_pD3D = NULL;
IDirect3DDevice9* g_pd3dDevice = NULL;
IDirect3DSurface9* g_pSurface = NULL;
HWND ghWnd = NULL;
RECT gScreenRect = { 0,0,0,0 };
UINT gPitch = 0;
void AddMouse(HDC hMemDC);
HRESULT GrabImage(void* bitmap);
//显示器个数
UINT _DisplayCount = 1;
public:
ScreenCapture9();
~ScreenCapture9();
//第几个显示器
HRESULT InitD3D(HWND hWnd,int nDisplay);
UINT GetPitch();
UINT GetHeight();
UINT GetWidth();
BYTE* Grab2Hwnd();
void Cleanup();
int InitDisplayCount();
//void test();
};
实现,注意抓取鼠标的方式有一点小问题,可自行修改
#include "ScreenCapture9.h"
#include "DGIWPlus.h"
//#include <d3dx9.h>
ScreenCapture9::ScreenCapture9()
{
CURSORINFO globalCursor;
globalCursor.cbSize = sizeof(CURSORINFO); // could cache I guess...
::GetCursorInfo(&globalCursor);
_hcur = globalCursor.hCursor;
//GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
}
ScreenCapture9::~ScreenCapture9()
{
//GdiplusShutdown(m_gdiplusToken);
}
int ScreenCapture9::InitDisplayCount()
{
if (g_pD3D == NULL)
{
if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
printf_s("Unable to Create Direct3D\\n");
return E_FAIL;
}
}
_DisplayCount = g_pD3D->GetAdapterCount();
return _DisplayCount;
}
HRESULT ScreenCapture9::InitD3D(HWND hWnd,int nDisplay)
{
D3DDISPLAYMODE ddm;
D3DPRESENT_PARAMETERS d3dpp;
if (g_pD3D == NULL)
{
if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
printf_s("Unable to Create Direct3D\\n");
return E_FAIL;
}
_DisplayCount = g_pD3D->GetAdapterCount();
}
if (nDisplay > _DisplayCount - 1)
{
nDisplay = D3DADAPTER_DEFAULT;
}
if (FAILED(g_pD3D->GetAdapterDisplayMode(nDisplay, &ddm)))
{
printf_s("Unable to Get Adapter Display Mode\\n");
return E_FAIL;
}
//g_pD3D->setA
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed = true;
d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dpp.BackBufferFormat = ddm.Format;
int width = ddm.Width; // rect.right - rect.left;
int height = ddm.Height; // rect.bottom - rect.top;
#if 1
d3dpp.BackBufferHeight = gScreenRect.bottom = ddm.Height;
d3dpp.BackBufferWidth = gScreenRect.right = ddm.Width;
#endif
#if 0
//gScreenRect = rect;
d3dpp.BackBufferHeight = ddm.Height;// rect.bottom - rect.top;
d3dpp.BackBufferWidth = ddm.Width; // rect.right - rect.left;
#endif
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
if (FAILED(g_pD3D->CreateDevice(nDisplay,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
//D3DCREATE_HARDWARE_VERTEXPROCESSING ,
&d3dpp, &g_pd3dDevice)))
{
printf_s("Unable to Create Device\\n");
return E_FAIL;
}
ghWnd = hWnd;
if (FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8,
D3DPOOL_SCRATCH, &g_pSurface, NULL)))
{
printf_s("Unable to Create Surface\\n");
return E_FAIL;
}
D3DLOCKED_RECT lockedRect;
if (FAILED(g_pSurface->LockRect(&lockedRect, NULL, 0))) // compute the required buffer size
{
printf_s("Unable to Lock Surface\\n");
return E_FAIL;
}
gPitch = lockedRect.Pitch;
if (FAILED(g_pSurface->UnlockRect()))
{
printf_s("Unable to Unlock Surface\\n");
return E_FAIL;
}
return S_OK;
}
UINT ScreenCapture9::GetPitch()
{
return gPitch;
}
UINT ScreenCapture9::GetHeight()
{
return gScreenRect.bottom - gScreenRect.top;
}
UINT ScreenCapture9::GetWidth()
{
return gScreenRect.right -gScreenRect.left;
}
void ScreenCapture9::AddMouse(HDC hMemDC) {
// __int64 start = StartCounter();
POINT p;
GetCursorPos(&p);
ICONINFO iconinfo;
BOOL ret = ::GetIconInfo(_hcur, &iconinfo); // 0.09ms
if (ret) {
p.x -= iconinfo.xHotspot; // align mouse, I guess...
p.y -= iconinfo.yHotspot;
// avoid some memory leak or other...
if (iconinfo.hbmMask) {
::DeleteObject(iconinfo.hbmMask);
}
if (iconinfo.hbmColor) {
::DeleteObject(iconinfo.hbmColor);
}
}
DrawIcon(hMemDC, p.x, p.y, _hcur); // 0.042ms
//if (show_performance)
// LocalOutput("add mouse took %.02f ms", GetCounterSinceStartMillis(start)); // sum takes around 0.125 ms
}
HRESULT ScreenCapture9::GrabImage(void* pBits)
{
if (FAILED(g_pd3dDevice->GetFrontBufferData(0, g_pSurface)))
{
printf_s("Unable to get Buffer Surface Data\\n");
return E_FAIL;
}
/*static int i = 0;
TCHAR buffer[256];
wsprintf(buffer, L"CaptureScreenByDirectDraw%d.bmp",i);*/
//D3DXSaveSurfaceToFile(buffer, D3DXIFF_BMP, g_pSurface, NULL, NULL);
//HDC hdc;
//HRESULT hok = g_pSurface->GetDC(&hdc);
//if (hok == S_OK)
//{
//AddMouse(hdc);
//}
D3DLOCKED_RECT lockedRect;
if (FAILED(g_pSurface->LockRect(&lockedRect, NULL, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY)))
{
printf_s("Unable to Lock Front Buffer Surface\\n");
return E_FAIL;
}
errno_t err;
int height = gScreenRect.bottom - gScreenRect.top ;
err = memcpy_s((BYTE*)pBits, lockedRect.Pitch*height, (BYTE*)lockedRect.pBits, lockedRect.Pitch*height);
if (err)
{
printf_s("Error executing memcpy_s.\\n");
}
if (FAILED(g_pSurface->UnlockRect()))
{
printf_s("Unable to Unlock Front Buffer Surface\\n");
return E_FAIL;
}
//g_pSurface->ReleaseDC(hdc);
return S_OK;
}
#if 0
HRESULT ScreenCapture9::Reset()
{
D3DDISPLAYMODE ddm;
D3DPRESENT_PARAMETERS d3dpp;
if (g_pSurface) //Release the Surface - we need to get the latest surface
{
g_pSurface->Release();
g_pSurface = NULL;
}
if (FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ddm))) //User might have changed the mode - Get it afresh
{
printf_s("Unable to Get Adapter Display Mode");
return E_FAIL;
}
//if (FAILED(g_pD3D->GetAdapterDisplayMode(1, &ddm))) //User might have changed the mode - Get it afresh
//{
// printf_s("Unable to Get Adapter Display Mode");
// return E_FAIL;
//}
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
d3dpp.Windowed = true;
d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dpp.BackBufferFormat = ddm.Format;
d3dpp.BackBufferHeight = gScreenRect.bottom = ddm.Height;
d3dpp.BackBufferWidth = gScreenRect.right = ddm.Width;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = ghWnd;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
if (FAILED(g_pd3dDevice->Reset(&d3dpp)))
{
printf_s("Unable to Reset Device");
return E_FAIL;
}
if (FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, /*D3DFMT_R8G8B8*/ D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &g_pSurface, NULL)))
{
printf_s("Unable to Create Surface");
return E_FAIL;
}
return S_OK;
}
#endif
void ScreenCapture9::Cleanup()
{
if (g_pSurface)
{
g_pSurface->Release();
g_pSurface = NULL;
}
if (g_pd3dDevice)
{
g_pd3dDevice->Release();
g_pd3dDevice = NULL;
}
if (g_pD3D)
{
g_pD3D->Release();
g_pD3D = NULL;
}
//if (_pPixel != NULL)
// delete[]_pPixel;
if(_hMemDC!=NULL)
DeleteDC(_hMemDC);
if(_hMemDCBitmap!=NULL)
DeleteObject(_hMemDCBitmap);
}
BYTE* ScreenCapture9::Grab2Hwnd()
{
int width = GetWidth();
int height = GetHeight();
int biBitCountchar = 32;
if (_initbitmap == 0)
{
HDC hDC = GetDC(ghWnd);
_initbitmap = 1;
ZeroMemory(&_bitmapinfo, sizeof(BITMAPINFO));
BITMAPINFOHEADER &bmiHeader = _bitmapinfo.bmiHeader;
bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmiHeader.biWidth = width;
bmiHeader.biHeight = 0 - height;
bmiHeader.biPlanes = 1;
bmiHeader.biBitCount = biBitCountchar; // 32 24;
bmiHeader.biXPelsPerMeter = 0;
bmiHeader.biYPelsPerMeter = 0;
bmiHeader.biSizeImage = width*height;
bmiHeader.biClrUsed = 0;
bmiHeader.biClrImportant = 0;
_hMemDC = CreateCompatibleDC(hDC);
_hMemDCBitmap = CreateDIBSection(_hMemDC, &_bitmapinfo, DIB_RGB_COLORS
, (void**)&_pPixel, NULL, 0);
SelectObject(_hMemDC, _hMemDCBitmap);
DeleteDC(hDC);
}
GrabImage(_pPixel);
AddMouse(_hMemDC);
//memcpy(_pPixel, pData, width*height*biBitCountchar / 8);
//if (hWnd != NULL)
//{
//BitBlt(hDC, 0, 0, width, height, _hMemDC, 0, 0, SRCCOPY);
//}
return _pPixel;
//pDestBuffer->Release();
}
main函数开始抓屏幕
int main()
{
ScreenCapture9* screenCapture9 = new ScreenCapture9();
RECT rect = { 0,0,1920,1080 };
screenCapture9->InitD3D(NULL,0);
int w = screenCapture9->GetPitch();
int h = screenCapture9->GetHeight();
//void* bitmap = malloc(w*h);
//WCHAR file[100];
char file[100];
GUID GUID_ContainerFormat = GUID_ContainerFormatPng; //Change the container format according to the file format we use eg:Bmp
BYTE *bitmap;
for (int i = 0; i < 100; i++)
{
DWORD t1 = GetTickCount();
bitmap = screenCapture9->Grab2Hwnd();
DWORD t2 = GetTickCount();
int len = screenCapture9->GetWidth() * 4 * screenCapture9->GetHeight();
#if 0
printf("the time is %d\\n", t2 - t1);
char * pbuffer = NULL;
int retlen = BMP2JPEG((char*)bitmap, len, &pbuffer);
if (pbuffer != NULL)
{
FILE * fp;
sprintf(file, "content\\\\GrabbedImage%d.jpg", i + 1);
fp = fopen(file, "wb");
if (fp != NULL)
{
fwrite(pbuffer, retlen, 1, fp);
fclose(fp);
}
}
#endif
//wsprintf(file, L"content\\\\GrabbedImage%d.png", i + 1);
//sprintf(file, "content\\\\GrabbedImage%d.bmp", i + 1);
//DGIPicStorage::SaveRgb2Bmp((char*)bitmap, screenCapture9->GetWidth(), screenCapture9->GetHeight(),32, file);
//SavePixelsToFile32bppPBGRA(screenCapture9->GetWidth(), screenCapture9->GetHeight(), screenCapture9->GetPitch(), (BYTE*)bitmap, file, GUID_ContainerFormatBmp);
SavePixelsToFile32bppPBGRA(screenCapture9->GetWidth(), screenCapture9->GetHeight(), screenCapture9->GetPitch(), (BYTE*)bitmap, file, GUID_ContainerFormatPng);
}
//free(bitmap);
screenCapture9->Cleanup();
return 0;
}
https://gitee.com/guanzhi0319/capture
以上是关于d3d9 抓取windows屏幕的主要内容,如果未能解决你的问题,请参考以下文章
javaCV开发详解之9:基于gdigrab的windows屏幕画面抓取/采集(基于javacv的屏幕截屏录屏功能)
javaCV开发详解之9补充篇2:基于x11grab的linux屏幕画面抓取/采集(linux录屏功能)