提高屏幕捕获性能

时间:2016-08-24 11:58:42

标签: 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* 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;
}

我的问题是循环中的代码执行时间太长。就我而言,每次迭代大约36毫秒。

我想知道是否有一些语句可以只执行一次,因此放在循环之外,对于字节缓冲区,我做了。我不知道哪些是我必须为每个新图像做的,哪些是我只能做一次的。

2 个答案:

答案 0 :(得分:0)

BitBltGetDIBits保留在循环中,将其余内容移动到循环外部,如下所示:

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);

此外,bmi.biSizeImage应设置为数据大小,在本例中为4 * ScreenX * ScreenY

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

您也可以尝试保存为24位位图。它不会对此代码产生任何影响,但数据大小会更小((width * bitcount + 31) / 32) * 4 * height)

答案 1 :(得分:0)

Windows的Aero功能似乎会影响BitBlt的速度。

如果从显示器上迭代一个BitBlt甚至一个像素,它将以每秒30帧的速度运行,并且CPU使用率将接近空闲状态。但是,如果关闭Windows的Aero功能,则会获得显着更快的BitBlt速度。