这一帧,只能是IDR帧。至于P帧和B帧,还不知道如何设置与之相关的引用参数。据说还得根据 pic_order_cnt 和 frame_num 自己编排播放顺序,我不能及。其实开发商业应用,前有FFmpeg,后有 Intel VAAPI ;还有外挂的 nvidia gstreamer,mesa gallium drivers 和 微软 Media Foundation。没必要班门弄斧,这里使用原生D3D12解码IDR帧,只是自娱自乐而已。首先在工程的App类里初始化COM组件:CoInitializeEx(nullptr,COINIT_APARTMENTTHREADED),然后初始化D3D12环境,为方便理解,都写在一个菜单项里:
RECT rc={0};
GetClientRect(&rc);
UINT width(rc.right-rc.left),height(rc.bottom-rc.top);
HWND hMainWnd(GetSafeHwnd());
HRESULT hr(E_INVALIDARG);
CComPtr<ID3D12Debug3> pD3DxDebug(nullptr);
hr=D3D12GetDebugInterface(IID_PPV_ARGS(&pD3DxDebug));
pD3DxDebug->SetEnableGPUBasedValidation(1);
pD3DxDebug->EnableDebugLayer();
CComPtr<ID3D12Device8> pD3DxDev(nullptr);
hr=D3D12CreateDevice(nullptr,D3D_FEATURE_LEVEL_12_1,IID_PPV_ARGS(&pD3DxDev));
// CComQIPtr<ID3D12DebugDevice> pD3DxDbgDev(pD3DxDev);
// hr=pD3DxDbgDev->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL);
CComPtr<IDXGIFactory7> pDXGIxFact(nullptr);
hr=CreateDXGIFactory2(0,IID_PPV_ARGS(&pDXGIxFact));
注释掉的部分用于观察调试信息,以下同。接下来创建三种命令队列,首先是普通命令队列:
D3D12_COMMAND_QUEUE_DESC CmdQue{};
CmdQue.Priority=D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
CmdQue.Type=D3D12_COMMAND_LIST_TYPE_DIRECT;
CmdQue.Flags=D3D12_COMMAND_QUEUE_FLAG_NONE;
CComPtr<ID3D12CommandQueue> pD3DxCmdQue(nullptr);
hr=pD3DxDev->CreateCommandQueue(&CmdQue,IID_PPV_ARGS(&pD3DxCmdQue));
CComPtr<ID3D12CommandAllocator> pCmdAlloc(nullptr);
hr=pD3DxDev->CreateCommandAllocator(CmdQue.Type,IID_PPV_ARGS(&pCmdAlloc));
CComPtr<ID3D12GraphicsCommandList6> pCmdList(nullptr);
hr=pD3DxDev->CreateCommandList(0,CmdQue.Type,pCmdAlloc,nullptr,IID_PPV_ARGS(&pCmdList));
第二是视频处理命令队列:
D3D12_COMMAND_QUEUE_DESC CmdQueVP{};
CmdQueVP.Priority=D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
CmdQueVP.Type=D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS;
CmdQueVP.Flags=D3D12_COMMAND_QUEUE_FLAG_NONE;
CComPtr<ID3D12CommandQueue> pD3DxVpsQue(nullptr);
hr=pD3DxDev->CreateCommandQueue(&CmdQueVP,IID_PPV_ARGS(&pD3DxVpsQue));
CComPtr<ID3D12CommandAllocator> pVpsAlloc(nullptr);
hr=pD3DxDev->CreateCommandAllocator(CmdQueVP.Type,IID_PPV_ARGS(&pVpsAlloc));
CComPtr<ID3D12VideoProcessCommandList2> pVpsCmdList(nullptr);
hr=pD3DxDev->CreateCommandList(0,CmdQueVP.Type,pVpsAlloc,nullptr,IID_PPV_ARGS(&pVpsCmdList));
最后是视频解码命令队列:
D3D12_COMMAND_QUEUE_DESC CmdQueVD{};
CmdQueVD.Priority=D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
CmdQueVD.Type=D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE;
CmdQueVD.Flags=D3D12_COMMAND_QUEUE_FLAG_NONE;
CComPtr<ID3D12CommandQueue> pD3DxVdeQue(nullptr);
hr=pD3DxDev->CreateCommandQueue(&CmdQueVD,IID_PPV_ARGS(&pD3DxVdeQue));
CComPtr<ID3D12CommandAllocator> pVdeAlloc(nullptr);
hr=pD3DxDev->CreateCommandAllocator(CmdQueVD.Type,IID_PPV_ARGS(&pVdeAlloc));
CComPtr<ID3D12VideoDecodeCommandList2> pVdeCmdList(nullptr);
hr=pD3DxDev->CreateCommandList(0,CmdQueVD.Type,pVdeAlloc,nullptr,IID_PPV_ARGS(&pVdeCmdList));
初始化继续,创建资源围栏,交换链,两种描述符堆,根签名,采样器,渲染shader,渲染管线,显示四边形,深度模板(若只显示平面视频图像,这个不是必须的),到此为止:
CComPtr<ID3D12Fence1> pD3DxFence(nullptr);
hr=pD3DxDev->CreateFence(0,D3D12_FENCE_FLAG_NONE,IID_PPV_ARGS(&pD3DxFence));
DXGI_SWAP_CHAIN_DESC1 scd{};
scd.Width=width,scd.Height=height;
scd.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.SwapEffect=DXGI_SWAP_EFFECT_FLIP_DISCARD;
scd.Format=DXGI_FORMAT_R8G8B8A8_UNORM;
scd.AlphaMode=DXGI_ALPHA_MODE_IGNORE;
scd.Scaling=DXGI_SCALING_STRETCH;
scd.SampleDesc.Quality=0;
scd.SampleDesc.Count=1;
scd.BufferCount=2;
scd.Stereo=0;
scd.Flags=0;
CComPtr<IDXGISwapChain1> pRelaySwap(nullptr);
hr=pDXGIxFact->CreateSwapChainForHwnd(pD3DxCmdQue,hMainWnd,&scd,nullptr,nullptr,&pRelaySwap);
CComQIPtr<IDXGISwapChain4> pSwapChain(pRelaySwap);
D3D12_DESCRIPTOR_HEAP_DESC RtvDesc{};
RtvDesc.NumDescriptors=scd.BufferCount;
RtvDesc.Type=D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
RtvDesc.Flags=D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
CComPtr<ID3D12DescriptorHeap> pRtvHeap(nullptr);
hr=pD3DxDev->CreateDescriptorHeap(&RtvDesc,IID_PPV_ARGS(&pRtvHeap));
UINT RtvDescSize(pD3DxDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
CD3DX12_CPU_DESCRIPTOR_HANDLE hRtvDesc(pRtvHeap->GetCPUDescriptorHandleForHeapStart());
vector<CComPtr<ID3D12Resource2>> RescRndr(scd.BufferCount);
for(UINT idx=0;idx<scd.BufferCount;++idx)
{
hr=pSwapChain->GetBuffer(idx,IID_PPV_ARGS(&RescRndr[idx]));
pD3DxDev->CreateRenderTargetView(RescRndr[idx],nullptr,hRtvDesc);
hRtvDesc.Offset(1,RtvDescSize);
}
D3D12_DESCRIPTOR_HEAP_DESC DsvDesc{};
DsvDesc.NumDescriptors=1;
DsvDesc.Type=D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
DsvDesc.Flags=D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
CComPtr<ID3D12DescriptorHeap> pDsvHeap(nullptr);
hr=pD3DxDev->CreateDescriptorHeap(&DsvDesc,IID_PPV_ARGS(&pDsvHeap));
UINT DsvDescSize(pD3DxDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV));
D3D12_DESCRIPTOR_HEAP_DESC CSUxvDesc{};
CSUxvDesc.NumDescriptors=1;
CSUxvDesc.Type=D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
CSUxvDesc.Flags=D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
CComPtr<ID3D12DescriptorHeap> pCSUxvHeap(nullptr);
hr=pD3DxDev->CreateDescriptorHeap(&CSUxvDesc,IID_PPV_ARGS(&pCSUxvHeap));
UINT CSUxvDescSize(pD3DxDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));
vector<CD3DX12_DESCRIPTOR_RANGE1> RngTab(1);
RngTab[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV,1,0,0);
vector<CD3DX12_ROOT_PARAMETER1> RootParm(1);
RootParm[0].InitAsDescriptorTable(1,&RngTab[0],D3D12_SHADER_VISIBILITY_PIXEL);
D3D12_FEATURE_DATA_ROOT_SIGNATURE SignVer{};
SignVer.HighestVersion=D3D_ROOT_SIGNATURE_VERSION_1_1;
if(FAILED(pD3DxDev->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE,&SignVer,sizeof(SignVer))))
{
SignVer.HighestVersion=D3D_ROOT_SIGNATURE_VERSION_1_0;
}
D3D12_STATIC_SAMPLER_DESC SmplDesc{};
SmplDesc.BorderColor=D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
SmplDesc.ShaderVisibility=D3D12_SHADER_VISIBILITY_PIXEL;
SmplDesc.ComparisonFunc=D3D12_COMPARISON_FUNC_ALWAYS;
SmplDesc.AddressU=D3D12_TEXTURE_ADDRESS_MODE_WRAP;
SmplDesc.AddressV=D3D12_TEXTURE_ADDRESS_MODE_WRAP;
SmplDesc.AddressW=D3D12_TEXTURE_ADDRESS_MODE_WRAP;
SmplDesc.Filter=D3D12_FILTER_ANISOTROPIC;
SmplDesc.MaxLOD=D3D12_FLOAT32_MAX;
SmplDesc.MaxAnisotropy=16;
SmplDesc.ShaderRegister=0;
SmplDesc.RegisterSpace=0;
SmplDesc.MipLODBias=0;
SmplDesc.MinLOD=0.f;
vector<D3D12_STATIC_SAMPLER_DESC> SmpList{SmplDesc};
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC RootSign{}; RootSign.Init_1_1(LODWORD(RootParm.size()),&RootParm[0],LODWORD(SmpList.size()),&SmpList[0],D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
CComPtr<ID3DBlob> pBlobSign(nullptr),pBlobErr(nullptr); hr=D3DX12SerializeVersionedRootSignature(&RootSign,SignVer.HighestVersion,&pBlobSign,&pBlobErr);
CComPtr<ID3D12RootSignature> pRootSign(nullptr);
hr=pD3DxDev->CreateRootSignature(0,pBlobSign->GetBufferPointer(),
pBlobSign->GetBufferSize(),IID_PPV_ARGS(&pRootSign));
CComPtr<ID3DBlob> pVShader(nullptr);
hr=D3DCompileFromFile(L"shadervp.hlsl",nullptr,nullptr,"VSMain","vs_5_1",
D3DCOMPILE_DEBUG|D3DCOMPILE_SKIP_OPTIMIZATION,0,&pVShader,nullptr);
CComPtr<ID3DBlob> pPShader(nullptr);
hr=D3DCompileFromFile(L"shadervp.hlsl",nullptr,nullptr,"PSMain