C++保存IMFSample为BMP图像失真问题求助
问题排查与解决方案
代码中的核心问题及修复方向:
1. BMP行字节对齐未处理
BMP格式强制要求每行像素数据的字节数为4的整数倍,你的代码直接用width*3计算行字节数,未做对齐处理,这是图像扭曲的主要原因之一。
修复方式:计算正确的行字节数
// 计算对齐后的每行字节数 int rowBytes = (format.imageWidthPels * 24 + 31) / 32 * 4; fileInfo.biSizeImage = rowBytes * format.imageHeightPels;
2. BITMAPFILEHEADER.bfSize计算错误
当前代码中fileHeader.bfSize的值完全不符合BMP规范,正确的文件总大小应该包含文件头、信息头和实际图像数据(含对齐)的总和:
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + fileInfo.biSizeImage;
3. 像素格式不匹配(关键原因)
从IMFSample获取的原始视频帧数据大概率不是RGB24格式(常见为YUV系列或BGRA等),直接按RGB24写入BMP必然导致颜色失真。你需要先将帧数据转换为RGB24格式:
- 通过
IMFSample->GetMediaType()获取当前帧的媒体类型,确认像素格式(如MFVideoFormat_NV12、MFVideoFormat_YUY2等) - 使用
IMFTransform创建格式转换器,将原始格式转换为MFVideoFormat_RGB24 - 转换后再提取数据写入BMP
4. 图像存储顺序颠倒
BMP默认从图像底部开始存储像素,而视频帧是从上到下的正序,直接写入会导致图像上下颠倒。修复时需要将像素行反转后再写入文件。
修正后的示例代码(包含对齐与顺序处理)
void SaveIMFSampleToBMP(IMFSample* pSample, FormatInfo format) { HANDLE file = CreateFile(LR"(C:\Users\soham.mittal\Desktop\Thumbnails\vids\sample.bmp)", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file == INVALID_HANDLE_VALUE) return; BITMAPFILEHEADER fileHeader = {0}; BITMAPINFOHEADER fileInfo = {0}; DWORD write = 0; // 计算对齐后的行字节数 int rowBytes = (format.imageWidthPels * 24 + 31) / 32 * 4; DWORD imageSize = rowBytes * format.imageHeightPels; // 填充文件头 fileHeader.bfType = 0x4D42; // 'BM' fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + imageSize; fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // 填充信息头 fileInfo.biSize = sizeof(BITMAPINFOHEADER); fileInfo.biWidth = format.imageWidthPels; fileInfo.biHeight = format.imageHeightPels; // 正数表示BMP倒序存储,后续需要反转行 fileInfo.biPlanes = 1; fileInfo.biBitCount = 24; fileInfo.biCompression = BI_RGB; fileInfo.biSizeImage = imageSize; fileInfo.biXPelsPerMeter = 2400; fileInfo.biYPelsPerMeter = 2400; // 写入头信息 WriteFile(file, &fileHeader, sizeof(fileHeader), &write, NULL); WriteFile(file, &fileInfo, sizeof(fileInfo), &write, NULL); IMFMediaBuffer* mediaBuffer = NULL; BYTE* pData = NULL; if (SUCCEEDED(pSample->ConvertToContiguousBuffer(&mediaBuffer)) && SUCCEEDED(mediaBuffer->Lock(&pData, NULL, NULL))) { // 注意:此处假设pData已经是RGB24格式,若不是需先转换 // 反转行顺序,适配BMP存储规则 BYTE* pRow = pData + (format.imageHeightPels - 1) * rowBytes; for (int i = 0; i < format.imageHeightPels; i++) { WriteFile(file, pRow, rowBytes, &write, NULL); pRow -= rowBytes; } mediaBuffer->Unlock(); } CloseHandle(file); SAFE_RELEASE(mediaBuffer); }
额外提示
- 必须先确认并转换像素格式:如果原始帧是YUV格式,直接写入RGB24会出现颜色混乱。可以参考微软Media Foundation的格式转换示例,使用
MFCreateTransform创建转换器。 - 检查
FormatInfo中的宽高是否正确,避免因尺寸错误导致的拉伸或扭曲。
内容的提问来源于stack exchange,提问作者Soham Mittal
相关产品推荐
相关产品推荐

