D3D12解码显示H.264的IDR帧图像

本文详细介绍了使用Direct3D 12 (D3D12) 原生解码并显示H.264编码的IDR帧图像的步骤。首先初始化COM组件和D3D12环境,接着创建三种命令队列:普通命令队列、视频处理命令队列和视频解码命令队列。接着创建资源、交换链、描述符堆、根签名等,并编译和设置渲染管线。最后通过读取H.264帧数据,解码并显示图像。这是一个自娱自乐的项目,展示了D3D12解码H.264 IDRI帧的能力。
摘要由CSDN通过智能技术生成

这一帧,只能是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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值