GDI 屏幕截图,结果在不同的计算机上有所不同

GDI Screenshot, results varying on different computer

我尝试用 GDI 截屏,然后在 FFmpeg 中使用它。 屏幕截图效果很好,FFmpeg 处理它没有任何问题。

但是,在某些计算机上,图像并不是我想要的,如下所示。

这是我用来初始化位图的代码:

//--
mImageBuffer = new unsigned char[mWxHxS];
memset(mImageBuffer, 0, mWxHxS);
//--
hScreenDC = GetDC(0);
hMemoryDC = CreateCompatibleDC(hScreenDC);
//--
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = 24;
bi.bmiHeader.biWidth = mWidth;
bi.bmiHeader.biHeight = mHeight;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biClrUsed = 24;
bi.bmiHeader.biClrImportant = 256;
hBitmap = CreateDIBSection(hMemoryDC, &bi, DIB_RGB_COLORS, &mImageBuffer, 0, 0);
SelectObject(hMemoryDC, hBitmap);

每个屏幕截图都在这里:

if(BitBlt(
    hMemoryDC,
    0,
    0,
    mWidth,
    mHeight,
    hScreenDC,
    mPx,
    mPy,
    SRCCOPY | CAPTUREBLT
))

我没有任何错误 运行 我的应用程序但是这个丑陋的图像并且只在某些计算机上。 我不知道在这些计算机上造成的区别是什么(所有都是 Win7,Aero 激活......)。 我不明白,因为我的代码遵循我发现的所有示例...

请帮帮我!

您正在创建设备独立位图 (CreateDIBSection),然后使用设备相关上下文 (CreateCompatibleDC) 来处理它。我相信您需要创建与 BitBlt 兼容的设备相关位图,或使用 StretchDIBits 来支持与设备无关的图像数据。这在某些计算机上有效而在其他计算机上无效的原因是视频驱动程序决定了设备相关图像的格式,它可能与设备无关图像的 Windows 定义相同也可能不同。

这是一个捕获图像的例子(是的,它不必要地长,但似乎仍然包含很好的信息):https://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx

这里是关于 StretchDIBits 的文档,如果您需要 DIB:https://msdn.microsoft.com/en-us/library/windows/desktop/dd145121(v=vs.85).aspx

所以我终于找到了解决方案:

在某些计算机上,BitBlt 和 StretchBlt 似乎并没有真正正确地处理 32 到 24 位之间的传输...

现在,我只使用 32 位的 GDI,让 FFmpeg 和 libswscale 将我的 RGBA 图像转换为 YUV 格式。

我的改动:

mWidth = GetDeviceCaps(hScreenDC, HORZRES);
mHeight = GetDeviceCaps(hScreenDC, VERTRES);
mWxHxS = mWidth*mHeight*4;

bi.bmiHeader.biBitCount = 32;
hBitmap = CreateCompatibleBitmap(hScreenDC, mWidth, mHeight);


if(BitBlt(
    hMemoryDC,
    0,
    0,
    mWidth,
    mHeight,
    hScreenDC,
    mPx,
    mPy,
    SRCCOPY | CAPTUREBLT
    ) && GetDIBits(hScreenDC, hBitmap, 0, mHeight, mImageBuffer, &bi, DIB_RGB_COLORS))
    {
    return true;
    }

感谢帮助我!