Maypeur
Maypeur

Reputation: 396

GDI Screenshot, results varying on different computer

I try to take a screenshot with GDI, then i use it in FFmpeg. The screenshot works well and FFmpeg handle it without any problem.

But, on some computer, the image is not very what i want like you can see below.

enter image description here

Here is the code i use to init my bitmap :

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

And here for each screenshot :

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

I do not have any error running my application but this ugly image and only on some computer. I don't know what is the difference causing that on these computer (All are Win7, Aero actived...). I do not understand because my code follow all example i found...

Please help me !

Upvotes: 3

Views: 465

Answers (2)

Maypeur
Maypeur

Reputation: 396

So i finaly find the solution :

It seems that the BitBlt and StretchBlt doesnt really handle correctly the transfer between 32 to 24 bits on some computers...

Now, i use only 32bits with GDI and let FFmpeg with libswscale convert my RGBA image to a YUV format.

My changes :

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

Thanks trying to help me !

Upvotes: 1

Matt Jordan
Matt Jordan

Reputation: 2181

You are creating a Device-Independent-Bitmap (CreateDIBSection) then using a Device Dependent Context (CreateCompatibleDC) to work with it. I believe you need to create a device dependent bitmap to be compatible with BitBlt, or use StretchDIBits to support device-independent image data. The reason this works on some computers and not others is because the video driver determines the format of a device-dependent image, which may or may not be the same as the Windows definition of a device-independent image.

Here is an example of capturing an image (yes, its unnecessarily long, but still seems to contain good info): https://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx

And here is documentation on StretchDIBits, in case you require a DIB: https://msdn.microsoft.com/en-us/library/windows/desktop/dd145121(v=vs.85).aspx

Upvotes: 3

Related Questions