屏幕截图核心代码(如果要求高帧率,请使用DxGI):
// RGB到YUV的转换公式
#define RGB_TO_Y(r, g, b) ((int)((0.299 * (r)) + (0.587 * (g)) + (0.114 * (b))))
#define RGB_TO_U(r, g, b) ((int)((-0.169 * (r)) - (0.331 * (g)) + (0.500 * (b)) + 128))
#define RGB_TO_V(r, g, b) ((int)((0.500 * (r)) - (0.419 * (g)) - (0.081 * (b)) + 128))
// 假设输入图像是32位ARGB,宽度为width,高度为height,如果是图像是RGB,下面像素位数4改为3即可
void ConvertRGBToYUV420P(unsigned char* rgbData, int width, int height, unsigned char* yuvData)
{
int ySize = width * height;
int uvSize = width * height / 4;
// 填充Y分量
for (int i = 0; i < height; ++i)
{
for (int j = 0; j < width; ++j)
{
int index = i * width + j;
yuvData[index] = RGB_TO_Y(rgbData[index * 4], rgbData[index * 4 + 1], rgbData[index * 4 + 2]);
}
}
// 填充U和V分量(下采样)
int uvIndex = ySize;
for (int i = 0; i < height; i += 2)
{
for (int j = 0; j < width; j += 2)
{
int rgbIndex = i * width + j;
yuvData[uvIndex++] = RGB_TO_U(rgbData[rgbIndex * 4], rgbData[rgbIndex * 4 + 1], rgbData[rgbIndex * 4 + 2]);
}
}
for (int i = 0; i < height; i += 2)
{
for (int j = 0; j < width; j += 2)
{
int rgbIndex = i * width + j;
yuvData[uvIndex++] = RGB_TO_V(rgbData[rgbIndex * 4], rgbData[rgbIndex * 4 + 1], rgbData[rgbIndex * 4 + 2]);
}
}
}
void SaveYUV420P(const char* filename, unsigned char* yuvBuffer, int width, int height)
{
FILE* file = fopen(filename, "wb");
if (!file)
{
AfxMessageBox(_T("Failed to open file for writing!"));
return;
}
int frameSize = width * height * 3 / 2;
fwrite(yuvBuffer, 1, frameSize, file);
fclose(file);
}
void SaveHBitmapToBmpFile(HBITMAP hBitmap, CString path)
{
// 定义文件头结构
BITMAPFILEHEADER fileHead;
int fileHeadLen = sizeof(BITMAPFILEHEADER);
// 定义图象信息结构
BITMAPINFOHEADER bmpHead;
int bmpHeadLen = sizeof(BITMAPINFOHEADER);
// 获取HBITMAP对象信息
BITMAP bmpObj;
GetObject(hBitmap, sizeof(BITMAP), &bmpObj);
// 计算文件总的字节大小
DWORD fileSizeInByte;
CDC srcDC;
srcDC.CreateDC(L"DISPLAY", NULL, NULL, NULL);
DWORD PixelSizeInBit = srcDC.GetDeviceCaps(BITSPIXEL) * srcDC.GetDeviceCaps(PLANES);
fileSizeInByte = fileHeadLen + bmpHeadLen + bmpObj.bmWidth * bmpObj.bmHeight * PixelSizeInBit / 8;
// 初始化文件头结构
fileHead.bfOffBits = fileHeadLen + bmpHeadLen;
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
fileHead.bfSize = fileSizeInByte;
fileHead.bfType = 0x4D42; // 'BM'
// 初始图像信息结构
bmpHead.biBitCount = PixelSizeInBit;
bmpHead.biClrImportant = 0;
bmpHead.biClrUsed = 0;
bmpHead.biCompression = BI_RGB;
bmpHead.biHeight = -bmpObj.bmHeight;//图像数据颠倒处理
bmpHead.biPlanes = 1;
bmpHead.biSize = bmpHeadLen;
bmpHead.biSizeImage = bmpObj.bmWidth * bmpObj.bmHeight * PixelSizeInBit / 8;
bmpHead.biWidth = bmpObj.bmWidth;
bmpHead.biXPelsPerMeter = 0;
bmpHead.biYPelsPerMeter = 0;
// 创建并打开BMP文件
CFile file;
if (!file.Open(path, CFile::modeCreate | CFile::modeWrite))
{
// 处理文件打开失败的情况
return;
}
// 写入文件头和图象信息头
file.Write(&fileHead, fileHeadLen);
file.Write(&bmpHead, bmpHeadLen);
// 获取位图数据并写入文件
BYTE* pBitmapBits = NULL;
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader = bmpHead;
HDC hDC = GetDC(NULL);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hBitmap);
pBitmapBits = new unsigned char[bmpHead.biSizeImage];
int nBits = GetDIBits(hDC, hBitmap, 0, bmpObj.bmHeight, pBitmapBits, &bmpInfo, DIB_RGB_COLORS);
file.Write(pBitmapBits, bmpHead.biSizeImage);
// 转换RGB到YUV420P
unsigned char* yuvBuffer = new unsigned char[bmpObj.bmWidth * bmpObj.bmHeight * 3 / 2];
ConvertRGBToYUV420P(pBitmapBits, bmpObj.bmWidth, bmpObj.bmHeight, yuvBuffer);
SaveYUV420P("d:\\a.yuv", yuvBuffer, bmpObj.bmWidth, bmpObj.bmHeight);
delete[] yuvBuffer;
// 恢复原来的位图对象并释放资源
SelectObject(hDC, hOldBitmap);
ReleaseDC(NULL, hDC);
delete[] pBitmapBits;
// 关闭文件
file.Close();
}
// 获取屏幕截图
HBITMAP CaptureScreen()
{
HDC hScreen = GetDC(NULL);
HDC hDC = CreateCompatibleDC(hScreen);
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
SelectObject(hDC, hBitmap);
BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);
return hBitmap;
}
void CaptureAndSaveScreenAsYUV420P(const char* filename)
{
HBITMAP hBitmap = CaptureScreen();
SaveHBitmapToBmpFile(hBitmap, _T("d:\\a.bmp"));
DeleteObject(hBitmap);
}
CaptureAndSaveScreenAsYUV420P("d:\\a.yuv");
该代码包含了抓取屏幕数据获取到HBITMAP对象,并根据HBITMAP对象获取到RGB数据,RGB数据可以保存bmp文件,也可以转换YUV420P后进行图像编码,具体如何使用,各取所需吧。