屏幕截圖核心代碼(如果要求高幀率,請使用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到YUV420Punsigned 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后進行圖像編碼,具體如何使用,各取所需吧。