Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 提高屏幕捕获性能_C_Performance_Winapi_Gdi - Fatal编程技术网

C 提高屏幕捕获性能

C 提高屏幕捕获性能,c,performance,winapi,gdi,C,Performance,Winapi,Gdi,我将创建某种“远程桌面”应用程序,通过套接字将屏幕内容流式传输到连接的客户端 为了截图,我提出了以下代码,这是我在这里和那里看到的示例的修改版本 #include <windows.h> #include <tchar.h> #include <stdio.h> int _tmain( int argc, _TCHAR * argv[] ) { int ScreenX = 0; int ScreenY = 0; BYTE* Scree

我将创建某种“远程桌面”应用程序,通过套接字将屏幕内容流式传输到连接的客户端

为了截图,我提出了以下代码,这是我在这里和那里看到的示例的修改版本

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

int _tmain( int argc, _TCHAR * argv[] )
{
    int ScreenX = 0;
    int ScreenY = 0;
    BYTE* ScreenData = 0;

    HDC hScreen = GetDC(GetDesktopWindow());

    ScreenX = GetDeviceCaps(hScreen, HORZRES);
    ScreenY = GetDeviceCaps(hScreen, VERTRES);
    ScreenData = (BYTE*)calloc(4 * ScreenX * ScreenY, sizeof(BYTE) );

    BITMAPINFOHEADER bmi = {0};
    bmi.biSize = sizeof(BITMAPINFOHEADER);
    bmi.biPlanes = 1;
    bmi.biBitCount = 32;
    bmi.biWidth = ScreenX;
    bmi.biHeight = -ScreenY;
    bmi.biCompression = BI_RGB;
    bmi.biSizeImage = 0; // 3 * ScreenX * ScreenY;


    int iBegTc = ::GetTickCount();

    // Take 100 screen captures for a more accurante measurement of the duration.
    for( int i = 0; i < 100; ++i )
    {
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, ScreenX, ScreenY);
        HDC hdcMem = CreateCompatibleDC (hScreen);
        HGDIOBJ hOld = SelectObject(hdcMem, hBitmap);
        BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hScreen, 0, 0, SRCCOPY);
        SelectObject(hdcMem, hOld);
        GetDIBits(hdcMem, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
        DeleteDC(hdcMem);
        DeleteObject(hBitmap);
    }

    int iEndTc = ::GetTickCount();

    printf( "%d ms", (iEndTc - iBegTc) / 100 );
    system("PAUSE");

    ReleaseDC(GetDesktopWindow(),hScreen);

    return 0;
}
#包括
#包括
#包括
int _tmain(int argc,_TCHAR*argv[]
{
int ScreenX=0;
int-ScreenY=0;
字节*屏幕数据=0;
HDC hsscreen=GetDC(GetDesktopWindow());
ScreenX=GetDeviceCaps(hsScreen,HORZRES);
ScreenY=获取设备CAPS(hs屏幕,垂直);
ScreenData=(字节*)calloc(4*ScreenX*ScreenY,sizeof(字节));
BitMapInfo标头bmi={0};
bmi.biSize=sizeof(BitMapInfo标头);
bmi.biPlanes=1;
bmi.biBitCount=32;
bmi.biWidth=ScreenX;
bmi.biHeight=-筛状;
bmi.biCompression=biu RGB;
bmi.biSizeImage=0;//3*ScreenX*ScreenY;
int iBegTc=::GetTickCount();
//拍摄100个屏幕截图,以更准确地测量持续时间。
对于(int i=0;i<100;++i)
{
HBITMAP HBITMAP=CreateCompatibleBitmap(hsscreen,ScreenX,ScreenY);
HDC hdcMem=CreateCompatibleDC(hs屏幕);
HGDIOBJ hOld=SelectObject(hdcMem、hBitmap);
BitBlt(hdcMem,0,0,ScreenX,ScreenY,hsscreen,0,0,srcopy);
选择对象(hdcMem,按住);
GetDIBits(hdcMem、hBitmap、0、ScreenY、ScreenData(BITMAPINFO*)和bmi、DIB_RGB_颜色);
DeleteDC(hdcMem);
删除对象(hBitmap);
}
int iEndTc=::GetTickCount();
printf(“%d ms”),(iEndTc-iBegTc)/100;
系统(“暂停”);
释放DC(GetDesktopWindow(),hs屏幕);
返回0;
}
我的问题是循环中的代码执行时间太长。在我的例子中,每次迭代大约36毫秒


我想知道是否有语句可以只执行一次,从而将其置于循环之外,就像我对字节缓冲区所做的那样。但是,我不知道我必须为每个新图像执行哪些操作,哪些操作只能执行一次。

BitBlt
GetDIBits
保留在循环内,将其余操作移到循环外,如下所示:

HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, ScreenX, ScreenY);
HDC hdcMem = CreateCompatibleDC (hScreen);
HGDIOBJ hOld = SelectObject(hdcMem, hBitmap);

for( int i = 0; i < 100; ++i )
{
    BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hScreen, 0, 0, SRCCOPY);
    //hBitmap is updated now
    GetDIBits(hdcMem, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
    //wait...
}

SelectObject(hdcMem, hOld);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
HBITMAP HBITMAP=CreateCompatibleBitmap(hsscreen,ScreenX,ScreenY);
HDC hdcMem=CreateCompatibleDC(hs屏幕);
HGDIOBJ hOld=SelectObject(hdcMem、hBitmap);
对于(int i=0;i<100;++i)
{
BitBlt(hdcMem,0,0,ScreenX,ScreenY,hsscreen,0,0,srcopy);
//hBitmap现已更新
GetDIBits(hdcMem、hBitmap、0、ScreenY、ScreenData(BITMAPINFO*)和bmi、DIB_RGB_颜色);
//等等。。。
}
选择对象(hdcMem,按住);
DeleteDC(hdcMem);
删除对象(hBitmap);
此外,
bmi.biSizeImage
应设置为数据大小,在这种情况下,
4*ScreenX*ScreenY

这不会使代码明显加快。瓶颈位于
BitBlt
。它仍然是大约30帧/秒,这应该可以,除非屏幕上有游戏或电影


您还可以尝试保存为24位位图。这段代码不会有任何区别,但数据大小会更小((宽度*比特数+31)/32)*4*高度)

Windows的Aero功能似乎会影响比特速度


如果您迭代地对显示器上的一个像素进行BitBlt,它将以每秒30帧的速度运行,CPU使用率将接近空闲。但是,如果你关闭Windows的Aero功能,你将获得更快的BitBlt速度。

不确定我是否收到你的评论”//拍摄100个屏幕截图,以便更准确地测量持续时间。”。我很确定for循环的前三行可以在循环之外完成不?到目前为止你尝试了什么?目前我还没有尝试在不知道的情况下改变事情。我怀疑,取决于我犯了什么错误,例如,由于某些内容没有更新,我可能会在每次迭代中都有相同的屏幕截图,而且因为在没有实际显示的情况下比较屏幕截图并不容易,所以盲目尝试是不现实的。我多次做这个循环,因为根据经验我知道GetTickCount并不总是非常精确的。如果它有时不准确15毫秒,那么这个测量误差将除以你的迭代次数。当然,但是为什么你总是分配一些昂贵的资源(循环的前3行),而不是重用它们?不分配资源肯定不会比分配资源慢,所以这也不是“盲目尝试”。正如我在第一条评论中所说的,我同意@IInspectable的观点,您可以尝试在for循环之外进行分配。这肯定不会影响您的实现。虽然这可能不足以获得足够好的时间性能,但它肯定会提高性能。当然Delete()也可以在外部完成。。。在这种情况下,不是盲目的测试,而是尝试做似乎最符合逻辑的事情。这就是我的观点:我不确定分配什么以及在循环之外可以做什么。当屏幕更新时,hScreen指向的DC也会更新?顺便说一句,你说前三行。这意味着我可以删除第五行?谢谢编辑:出于某种原因,在将前3行和最后2行移出循环并注释掉第5行之后,每次迭代需要额外10毫秒,奇怪。谢谢你的回答。我做了类似的事情,但不幸的是,BitBlt占用了很大一部分计算时间,对于我的需求来说太慢了。我必须找到另一种方法来实现这一点。还有其他选项,例如DirectX游戏,但据我所知,
BitBlt
是远程桌面的唯一选项。您可以为鼠标和键盘添加钩子,只有在用户输入后才进行屏幕截图,这将大大提高性能,除非窗口在屏幕上绘制一些图形,否则应该可以