VC bitblt截屏性能问题

kooyou68 2012-04-19 07:08:37
最近在做一个关于屏幕监控的应用,发现用bitblt截屏,1366*768大小的屏幕截屏下来要用到50ms左右。而就算是截一个1*1大小的也要22ms,请问这是怎么回事?
另外有其它较好的截屏方法么?

截屏的代码如下:

HDC hDC=::GetDC(NULL);
HDC hMemDC=CreateCompatibleDC(hDC);
HBITMAP hBitmap=CreateCompatibleBitmap(hDC,width,height);
HBITMAP hOldBitmap;
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);
BitBlt(hMemDC,0,0,width,height,hDC,left,right,SRCCOPY);
...全文
1131 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
e我行 2013-08-31
  • 打赏
  • 举报
回复
楼主的DX截屏方式说的不对吧, //注意: //相对比较费时间的函数是mv_pd3dDevice->GetFrontBufferData(0, mv_pSurface); //大概用掉50ms左右,所以不要每次截获屏幕都运行一次 mv_pd3dDevice->GetFrontBufferData这个必须每截一次就运行一次,不然就始终是第一次的图像,不知道你试过没?
fkseraph 2013-07-15
  • 打赏
  • 举报
回复
大神有mirror截屏的实例吗?我正在学习中。
老衲爱上树 2013-06-29
  • 打赏
  • 举报
回复
可以用mirror方式,mirror在ddk中编译,是一个虚拟显卡驱动,可以在20ms内完成截屏
kooyou68 2012-08-12
  • 打赏
  • 举报
回复
bitblt函数是无法提升速度的
bweaglegao 2012-08-08
  • 打赏
  • 举报
回复
请问,bitblt函数可以提高到20ms以内么?
kooyou68 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]
引用 12 楼 的回复:
你把代码上传看看,为什么我之前用d3d截屏比BitBlt要慢

d3d应该有硬件加速吧
[/Quote]
确实有硬件加速
向立天 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]
你把代码上传看看,为什么我之前用d3d截屏比BitBlt要慢
[/Quote]
d3d应该有硬件加速吧
kooyou68 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 的回复:]
每秒刷新25次人眼就不易分辨了,你截那么快没多大意义
[/Quote]
哎。项目的性能要求至少30帧每秒啊!
其实现在屏幕一般都40帧以上的,游戏要求就更高了。。
Lactoferrin 2012-04-21
  • 打赏
  • 举报
回复
每秒刷新25次人眼就不易分辨了,你截那么快没多大意义
kooyou68 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 的回复:]
hook消息只能截获有限的图像更新,mirror驱动会禁用掉桌面组合
监控主要慢在网络传输上,不是截图的速度
所以应该减少传送的数据,可以用分块比较传输,xor,隔行扫描,差分,有损压缩
[/Quote]
我觉得你这样讲不对。截屏-压缩-传输,这些环节每个都很重要。就好像我现在讨论的截屏,如果截屏一次用掉20ms的话,你一秒钟最多可以截50次,如果用隔行扫描,或者hooks,这50次恐怕都不够用。另外还要xor运算和压缩,这些都是需要时间的,你每一次都为了减少传输量而做大量的运算,甚至截屏N多次,那么你一秒钟能发送多少帧?
当然了,xor是比较有用,隔行扫描我也试过,缺点在于截屏太多次,而且碎片多。有损压缩同样费时间。

不过,谢谢Lactoferrin的热心帮助,结贴。
Lactoferrin 2012-04-21
  • 打赏
  • 举报
回复
hook消息只能截获有限的图像更新,mirror驱动会禁用掉桌面组合
监控主要慢在网络传输上,不是截图的速度
所以应该减少传送的数据,可以用分块比较传输,xor,隔行扫描,差分,有损压缩
kooyou68 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 的回复:]
你每次都截全屏,当然耗的时候比较长,远程屏幕监控,肯定是要做到差异截屏的,也是使用的BITBLT函数,如果想要更好的性能,可以使用MIRROR驱动,建议参考下VNC的代码,开源的,他使用的HOOK消息,MIRROR驱动的也有,不过驱动程序不是开源的
[/Quote]
并不是每次都截全屏。
另外,VNC的hook我也在用了。
lqfcu2 2012-04-21
  • 打赏
  • 举报
回复
你每次都截全屏,当然耗的时候比较长,远程屏幕监控,肯定是要做到差异截屏的,也是使用的BITBLT函数,如果想要更好的性能,可以使用MIRROR驱动,建议参考下VNC的代码,开源的,他使用的HOOK消息,MIRROR驱动的也有,不过驱动程序不是开源的
kooyou68 2012-04-21
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]
你把代码上传看看,为什么我之前用d3d截屏比BitBlt要慢
[/Quote]


/*先运行InitDX(),之后直接调用GetBmpFromRectDX(RECT)函数截取相应的区域即可*/

//注意:
//相对比较费时间的函数是mv_pd3dDevice->GetFrontBufferData(0, mv_pSurface);
//大概用掉50ms左右,所以不要每次截获屏幕都运行一次

////////DX
BOOL CBmpManager::InitDX()
{
///初始化变量
mv_pD3D=NULL;
mv_pd3dDevice=NULL;
mv_pSurface=NULL;
mv_screenRect.left=0;
mv_screenRect.right=0;
mv_screenRect.top=0;
mv_screenRect.bottom=0;
mv_bCapturing=false;
mv_pBits=NULL;
mv_hBackDC=NULL;
mv_hBackBitmap=NULL;
mv_hOldBitmap=NULL;

if(FAILED(InitD3D(NULL))){
AfxMessageBox(_T("Failed to InitD3D!"));
return FALSE;
}
return TRUE;
}

HRESULT CBmpManager::InitD3D(HWND hWnd)
{
D3DDISPLAYMODE ddm;
D3DPRESENT_PARAMETERS d3dpp;

if((mv_pD3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
{
AfxMessageBox(_T("Unable to Create Direct3D "));
return E_FAIL;
}

if(FAILED(mv_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
{
AfxMessageBox(_T("Unable to Get Adapter Display Mode"));
return E_FAIL;
}
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));

d3dpp.Windowed=WINDOW_MODE;
d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dpp.BackBufferFormat=ddm.Format;
d3dpp.BackBufferHeight=mv_nDisplayHeight=mv_screenRect.bottom =ddm.Height;
d3dpp.BackBufferWidth=mv_nDisplayWidth=mv_screenRect.right =ddm.Width;
d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow=hWnd;
d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;

if(FAILED(mv_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dpp,&mv_pd3dDevice)))
{
AfxMessageBox(_T("Unable to Create Device"));
return E_FAIL;
}

if(FAILED(mv_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &mv_pSurface, NULL)))
{
AfxMessageBox(_T("Unable to Create Surface"));
return E_FAIL;
}


mv_pd3dDevice->GetFrontBufferData(0, mv_pSurface);

return S_OK;
}


LPD3DXBUFFER CBmpManager::GetBmpFromRectDX(CRect cRect)
{
LPD3DXBUFFER lpD3DBuf;

RECT rect;
rect.left=cRect.left;
rect.top=cRect.top;
rect.bottom=cRect.bottom;
rect.right=cRect.right;

CString szFileName;
static int i=0;
szFileName.Format(_T("hooksBmp/ScreenShot%d.jpg"),i++);
D3DXSaveSurfaceToFile(szFileName,D3DXIFF_JPG,mv_pSurface,NULL,&rect);
//Save to File


return lpD3DBuf;
}
Lactoferrin 2012-04-20
  • 打赏
  • 举报
回复
你把代码上传看看,为什么我之前用d3d截屏比BitBlt要慢
kooyou68 2012-04-20
  • 打赏
  • 举报
回复
跟进:
今晚用DirectX来截屏,效率大有改进:1366*768大约12ms
kooyou68 2012-04-20
  • 打赏
  • 举报
回复
确实是Bitblt的问题,我今天在机房(机械性能:XP,E8400 3.00GHz,3GB,DX9.0c,显存256MB,1280*1024)也测试过了,1280*1024全屏截屏平均耗时30ms,在WIN7系统下平均耗时33ms,而且连续截屏是基本卡住动不了。
现在用DirectDraw来试试,看能不能提升下速度!
有哪位试过的来给点意见?
kooyou68 2012-04-20
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]
你这把
HDC hDC=::GetDC(NULL);
HDC hMemDC=CreateCompatibleDC(hDC);
HBITMAP hBitmap=CreateCompatibleBitmap(hDC,width,height);
HBITMAP hOldBitmap;
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitma……
[/Quote]
将局部变量提取出来后的Test函数如下:

void CTestView::OnTest()
{
int timeDiff=0;
int times=150;
int width=1366;
int height=768;
int left=0;
int right=0;

HDC hDC=::GetDC(NULL);
HDC hMemDC=CreateCompatibleDC(hDC);
HBITMAP hBitmap=CreateCompatibleBitmap(hDC,width,height);
HBITMAP hOldBitmap;
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);

LARGE_INTEGER m_liPerfFreq={0};
//获取每秒多少CPU Performance Tick
QueryPerformanceFrequency(&m_liPerfFreq);


LARGE_INTEGER liPerfStart={0};
QueryPerformanceCounter(&liPerfStart);

for(int i=0;i<times;i++){
BitBlt(hMemDC,0,0,width,height,hDC,left,right,SRCCOPY);
}

LARGE_INTEGER liPerfEnd={0};
QueryPerformanceCounter(&liPerfEnd);

int time=(((liPerfEnd.QuadPart -
liPerfStart.QuadPart) * 1000)/m_liPerfFreq.QuadPart);

CString timeStr;
timeStr.Format(_T("%d"),time/times);
AfxMessageBox(timeStr);
}

运行150次,1366*768大小的截屏,平均消耗时间还是50ms左右。
哎,有什么办法呢。
Tinary3v0 2012-04-19
  • 打赏
  • 举报
回复
HDC hDC=::GetDC(NULL);
HDC hMemDC=CreateCompatibleDC(hDC);
HBITMAP hBitmap=CreateCompatibleBitmap(hDC,width,height);
HBITMAP hOldBitmap;
hOldBitmap=(HBITMAP)SelectObject( hMemDC,hBitmap );

上面这些临时变量全部改成全局变量或者类成员函数,不要再函数中,每次都生成、销毁。
测试的时候看速度最好看平均值,每100次或者200次取一下平均。
Lactoferrin 2012-04-19
  • 打赏
  • 举报
回复
HDC hDC=::GetDC(NULL);
HDC hMemDC=CreateCompatibleDC(hDC);
HBITMAP hBitmap=CreateCompatibleBitmap(hDC,width,height);
HBITMAP hOldBitmap;
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);
这个只是准备工作,连续截屏时只需用BitBlt
加载更多回复(5)

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧