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

基于D3D11+MediaFoundation的MP4录制:RGB32转NV12疑问

关于D3D11+MediaFoundation录制MP4时RGB32转NV12的兼容性与实现方案

我来结合MediaFoundation和D3D11的实际开发经验,给你拆解这些问题:

一、是否必须将MFVideoFormat_RGB32转换为MFVideoFormat_NV12?

结论:从兼容性和稳定性角度,强烈建议转换为NV12

你当前的方案在测试机器上能跑,是因为这些机器的MediaFoundation环境(系统版本、硬件编码器)恰好支持RGB32输入到H264编码器,但这不是通用情况:

  • 部分老硬件(比如Win7时代的低端显卡)的硬件H264编码器可能只接受YUV类格式(尤其是NV12),不支持RGB32直接输入。
  • 某些精简版Win7/8系统可能缺失了RGB转YUV的系统MFT,导致编码器无法处理RGB32输入,直接返回错误。
  • NV12是目前MediaFoundation生态中支持最广泛的视频格式,Intel、AMD、NVIDIA的硬件编码器对它的硬件加速支持都非常完善,是录制场景的最优选择。

二、RGB32转NV12的实现方案

结合你的D3D11场景,推荐两种高效的实现方式:

1. 利用MediaFoundation内置转换MFT(自动/手动)

自动方式(最简单)

你可以保持当前的InitVideoStreamHelper代码不变,但去掉手动注册CColorConvertDMO的逻辑(这个是旧版DMO,效率不如新的MFT)。当SinkWriter发现输入类型(RGB32)和输出类型(H264要求的YUV)不匹配时,会自动尝试加载系统内置的视频转换MFT来完成格式转换。

手动方式(更可控)

如果需要更稳定的转换流程,可以手动创建转换MFT:

// 示例:创建RGB32转NV12的转换MFT
HRESULT CreateColorConvertMFT(IMFTransform** ppMFT, UINT32 width, UINT32 height) {
    HRESULT hr = S_OK;
    MFT_REGISTER_TYPE_INFO inputType = { MFMediaType_Video, MFVideoFormat_RGB32 };
    MFT_REGISTER_TYPE_INFO outputType = { MFMediaType_Video, MFVideoFormat_NV12 };
    
    // 查找支持硬件加速的转换MFT
    CComPtr<IMFActivate> pActivate;
    hr = MFTEnumEx(MFT_CATEGORY_VIDEO_PROCESSOR, 
                   MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SYNCMFT,
                   &inputType, &outputType,
                   NULL, &pActivate);
    if (FAILED(hr)) {
        // fallback到软件MFT
        hr = MFTEnumEx(MFT_CATEGORY_VIDEO_PROCESSOR,
                       MFT_ENUM_FLAG_SYNCMFT,
                       &inputType, &outputType,
                       NULL, &pActivate);
    }
    if (SUCCEEDED(hr)) {
        hr = pActivate->ActivateObject(__uuidof(IMFTransform), (void**)ppMFT);
    }
    return hr;
}

之后在MakeVideoFrame中,先把RGB32的媒体帧输入到MFT,获取NV12的输出帧,再传给SinkWriter。

2. D3D11硬件加速转换(性能最优)

因为你的纹理都是D3D11资源,用GPU直接转换效率最高,步骤如下:

  1. 创建NV12格式的目标纹理:
D3D11_TEXTURE2D_DESC nv12Desc = {};
nv12Desc.Width = uiWidth;
nv12Desc.Height = uiHeight;
nv12Desc.Format = DXGI_FORMAT_NV12;
nv12Desc.ArraySize = 1;
nv12Desc.MipLevels = 1;
nv12Desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
nv12Desc.Usage = D3D11_USAGE_DEFAULT;
nv12Desc.SampleDesc.Count = 1;
hr = _d3d_device->CreateTexture2D(&nv12Desc, NULL, &_nv12_texture2d);
  1. 使用D3D11视频处理器完成转换:
// 初始化视频处理器(只需要做一次)
CComPtr<ID3D11VideoDevice> pVideoDevice;
hr = _d3d_device->QueryInterface(&pVideoDevice);

D3D11_VIDEO_PROCESSOR_CONTENT_DESC contentDesc = {};
contentDesc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
contentDesc.InputWidth = uiWidth;
contentDesc.InputHeight = uiHeight;
contentDesc.OutputWidth = uiWidth;
contentDesc.OutputHeight = uiHeight;
contentDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;

CComPtr<ID3D11VideoProcessorEnumerator> pEnumerator;
hr = pVideoDevice->CreateVideoProcessorEnumerator(&contentDesc, &pEnumerator);

CComPtr<ID3D11VideoProcessor> pVideoProcessor;
hr = pVideoDevice->CreateVideoProcessor(pEnumerator, 0, &pVideoProcessor);

// 转换纹理
CComPtr<ID3D11DeviceContext> pContext;
_d3d_device->GetImmediateContext(&pContext);

D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputViewDesc = {};
inputViewDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
inputViewDesc.Texture2D.MipSlice = 0;
CComPtr<ID3D11VideoProcessorInputView> pInputView;
hr = pVideoDevice->CreateVideoProcessorInputView(_capture_texture2d, pEnumerator, &inputViewDesc, &pInputView);

D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputViewDesc = {};
outputViewDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
outputViewDesc.Texture2D.MipSlice = 0;
CComPtr<ID3D11VideoProcessorOutputView> pOutputView;
hr = pVideoDevice->CreateVideoProcessorOutputView(_nv12_texture2d, pEnumerator, &outputViewDesc, &pOutputView);

// 执行转换
pContext->VideoProcessorBlt(pVideoProcessor, pOutputView, 0, 1, &pInputView, NULL, NULL);
  1. 将NV12纹理包装成MediaFoundation媒体帧,传给SinkWriter即可(类似你当前MakeVideoFrame中Win8+的逻辑,用MFCreateDXGISurfaceBuffer)。

三、Win7/8/10系统的内置支持情况

系统版本硬件加速转换支持备注
Win10✅ 完全支持内置的视频转换MFT和D3D11视频处理器都支持RGB32→NV12的硬件加速,只要显卡支持DXGI 1.2+
Win8/8.1✅ 支持D3D11视频处理器支持硬件加速转换,系统内置转换MFT也兼容
Win7⚠️ 有限支持需要满足两个条件:
1. 安装KB2670838补丁,启用D3D11.1支持;
2. 显卡驱动支持DXGI_FORMAT_NV12的硬件转换;
如果不满足,只能使用软件转换(比如CColorConvertDMO)

代码修改建议

如果你决定转成NV12,需要修改InitVideoStreamHelper中的输入媒体类型:

// 修改输入类型为NV12
hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);

然后在MakeVideoFrame中加入上述的转换逻辑,将_capture_texture2d(RGB32)转成NV12纹理,再包装成媒体帧。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:29:44