You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

额外提示

  1. 必须先确认并转换像素格式:如果原始帧是YUV格式,直接写入RGB24会出现颜色混乱。可以参考微软Media Foundation的格式转换示例,使用MFCreateTransform创建转换器。
  2. 检查FormatInfo中的宽高是否正确,避免因尺寸错误导致的拉伸或扭曲。

内容的提问来源于stack exchange,提问作者Soham Mittal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 01:35:24