D3D11 有一个视频 api,它基本上是 DXVA2,上面的界面略有改变。您需要很好地了解 h.264 比特流才能继续(真的!)。即确保您手头有一个 h.264 解析器来提取 SPS 和 PPS 结构的字段以及编码帧的所有切片。
1) 从您的 ID3D11Device 中获取 ID3D11VideoDevice 实例,并从您的直接 D3D11 设备上下文中获取 ID3D11VideoContext 注意:在 Win7 上,您必须创建功能级别为 9_3 的设备才能获得视频支持!(在Win8中它只是工作)
2) 为 h.264 创建一个 ID3D11VideoDecoder 实例 使用 ID3D11VideoDevice::GetVideoDecoderProfileCount, GetVideoDecoderProfile, CheckVideoDecodeRFormat... 遍历所有支持的配置文件,并为没有胶片颗粒的 h264 找到一个具有 GUID D3D11_DECODER_PROFILE_H264_VLD_NOFGT 的配置文件。作为 OutputFormat,您最好的选择是 DXGI_FORMAT_NV12。
3) 单个帧的解码请参阅Supporting Direct3D 11 Video Decoding in Media Foundation:
- ID3D11VideoContext::DecoderBeginFrame(decoder, outputView -> 解码帧纹理)
- 填充缓冲区:
- D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS
- D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX
- D3D11_VIDEO_DECODER_BUFFER_BITSTREAM
- D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL
缓冲区填充有相应的 DXVA2 结构(请参阅 dxva2.h) 完整的 DXVA2 规范在这里,您需要它来相应地映射 h.264 sps/pps 字段。
看:
然后:
- ID3D11VideoContext::SubmitBuffers 提交所有填充的缓冲区
- ID3D11VideoContext::DecoderEndFrame 完成当前帧
3) D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS 缓冲区还包含所有参考帧/表面的信息 - 您需要自己管理它们,即确保表面/纹理可用于 GPU!
这很复杂,检查 ffmpeg 和 Media Player Classic,它们都支持 DXVA2(虽然不是通过 DX11)。
4) 从 NV12 转换为 RGB(A),有些 GPU(D3D11 特征级别)允许使用 NV12 作为着色器输入,有些则不允许。如果无法直接使用 NV12,请查看 D3D11VideoProcessor 接口,该接口具有 NV12/YUV420->RGB 转换功能,适用于所有支持 D3D11 的 GPU。
可以在如下代码中执行转换:
// Setup ID3D11Video*
ID3D11VideoProcessor * d3dVideoProc = ...;
ID3D11VideoDevice * d3dVideoDevice = ...;
ID3D11VideoProcessorEnumerator * d3dVideoProcEnum = ...;
ID3D11Texture2D * srcTextureNV12Fmt = ...;
ID3D11Texture2D * dstTextureRGBFmt = ...;
// Use Video Processor
// Create views for VideoProc In/Output
ID3D11VideoProcessorInputView * videoProcInputView;
ID3D11VideoProcessorOutputView * videoProcOutputView;
{
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputViewDesc = { 0 };
inputViewDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
inputViewDesc.Texture2D.ArraySlice = arraySliceIdx;
inputViewDesc.Texture2D.MipSlice = 0;
hr = d3dVideoDevice->CreateVideoProcessorInputView(srcTextureNV12Fmt, d3dVideoProcEnum, &inputViewDesc, &videoProcInputView);
}
{
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputViewDesc = { D3D11_VPOV_DIMENSION_TEXTURE2D };
outputViewDesc.Texture2D.MipSlice = 0;
hr = d3dVideoDevice->CreateVideoProcessorOutputView(dstTextureRGBFmt, d3dVideoProcEnum, &outputViewDesc, &videoProcOutputView);
}
// Setup streams
D3D11_VIDEO_PROCESSOR_STREAM streams = { 0 };
streams.Enable = TRUE;
streams.pInputSurface = videoProcInputView.get();
RECT srcRect = { /* source rectangle in pixels*/ };
RECT dstRect = { /* destination rectangle in pixels*/ };
// Perform VideoProc Blit Operation (with color conversion)
hr = videoCtx_->VideoProcessorBlt(d3dVideoProc, videoProcOutputView.get(), 0, 1, &streams);