导读
本文适合对FFmpeg和DX有所了解的新手。
以下的文章包括从FFmpeg解码到DirectComposition上屏的两种实现方式。
正文
一、利用SwapChain上屏
1.创建设备并绑定交换链
//创建DXGI工厂
ComPtr<IDXGIFactory4> factory;
CreateDXGIFactory1(IID_PPV_ARGS(&factory));
//创建D3D设备
D3D_FEATURE_LEVEL featureLevelSupported;
D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, d3dDevice.GetAddressOf(), &featureLevelSupported, nullptr);
ComPtr<IDXGIDevice> dxgiDevice;
d3dDevice.As(&dxgiDevice);
//创建DirectComposition设备
ComPtr<IDCompositionDesktopDevice> pDcomDevice;
DCompositionCreateDevice3(dxgiDevice.Get(), IID_PPV_ARGS(&pDcomDevice));
// 交换链描述符
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = 2;
swapChainDesc.Width = m_width;
swapChainDesc.Height = m_height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT |
DXGI_USAGE_BACK_BUFFER;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
//创建交换链
ComPtr<IDXGISwapChain1> swapChain;
HRESULT hr = (factory->CreateSwapChainForComposition(
d3dDevice.Get(),
&swapChainDesc,
nullptr,
&swapChain
));
//根据窗口句柄创建DirectCompositionTarget
pDcomDevice->CreateTargetForHwnd(m_hWnd,true, m_target.ReleaseAndGetAddressOf());
//创建Visual
pDcomDevice->CreateVisual(m_visual.ReleaseAndGetAddressOf());
//visual绑定交换链
m_visual->SetContent(swapChain.Get());
//设置根visual
m_target->SetRoot(m_visual.Get());
pDcomDevice->Commit();
2.更新交换链缓冲区实现上屏
//获取D3D设备上下文
ComPtr<ID3D11DeviceContext> pContext;
d3dDevice->GetImmediateContext(pContext.ReleaseAndGetAddressOf());
//获取交换链缓冲区
ComPtr<IDXGISurface> surface;
m_swapChain->GetBuffer(0, __uuidof(IDXGISurface), reinterpret_cast<void**>(surface.GetAddressOf()));
ComPtr<ID3D11Texture2D> dc;
surface.As(&dc);
//拷贝纹理到交换链缓冲区
pContext->CopyResource(dc.Get(), m_pD3DTexture.Get());
//上屏
m_swapChain->Present(1, 0);
二、利用DCompositionSurface上屏
1.创建设备并绑定DirectCompositionSurface
//创建DXGI工厂
ComPtr<IDXGIFactory4> factory;
CreateDXGIFactory1(IID_PPV_ARGS(&factory));
//创建D3D设备
D3D_FEATURE_LEVEL featureLevelSupported;
D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, d3dDevice.GetAddressOf(), &featureLevelSupported, nullptr);
ComPtr<IDXGIDevice> dxgiDevice;
d3dDevice.As(&dxgiDevice);
//创建d2d设备
ComPtr<ID2D1Device> d2dDevice;
D2D1CreateDevice(dxgiDevice.Get(),D2D1::CreationProperties(D2D1_THREADING_MODE_SINGLE_THREADED, D2D1_DEBUG_LEVEL_NONE,
D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS), &d2dDevice);
//利用d2d设备创建DirectComposition设备
ComPtr<IDCompositionDesktopDevice> pDcomDevice;
DCompositionCreateDevice3(d2dDevice.Get(), IID_PPV_ARGS(&pDcomDevice));
//创建DCompositionSurface
pDcomDevice->CreateVirtualSurface(m_width, m_height, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_ALPHA_MODE_PREMULTIPLIED, &m_surface);
//根据窗口句柄创建DirectCompositionTarget
pDcomDevice->CreateTargetForHwnd(m_hWnd,true, m_target.ReleaseAndGetAddressOf());
//创建Visual
pDcomDevice->CreateVisual(m_visual.ReleaseAndGetAddressOf());
//visual绑定交换链
m_visual->SetContent(m_surface.Get());
//设置根visual
m_target->SetRoot(m_visual.Get());
pDcomDevice->Commit();
2.ID3D11Texture2D转ID2D1Bitmap
//用于内存映射的纹理
ComPtr<ID3D11Texture2D> pTempTex;
D3D11_TEXTURE2D_DESC texDesc;
m_pD3DTexture->GetDesc(&texDesc);
texDesc.BindFlags = 0;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; //CPU可读
texDesc.Usage = D3D11_USAGE_STAGING;
m_pd3dDevice->CreateTexture2D(&texDesc, NULL, pTempTex.GetAddressOf());
m_pd3dDeviceContex->CopyResource(pTempTex.Get(), m_pD3DTexture.Get());
D3D11_MAPPED_SUBRESOURCE mappedResource;
//内存映射
m_pd3dDeviceContex->Map(pTempTex.Get(), 0, D3D11_MAP_READ, 0, &mappedResource);
//一幅待显示位图
ComPtr<ID2D1Bitmap> pBmp;
POINT offset = {0, 0};
ComPtr<ID2D1DeviceContext> dc;
//BeginDraw返回d2d设备上下文,需要注意Surface与D2D设备关联
m_pDCompSurface->BeginDraw(nullptr, IID_PPV_ARGS(&dc), &offset);
//d2d渲染对象
ComPtr<ID2D1RenderTarget> pRT;
dc.As(&pRT);
//设置一些位图属性
D2D1_SIZE_U size = D2D1::SizeU(texDesc.Width, texDesc.Height);
D2D1_BITMAP_PROPERTIES bmpprops;
bmpprops.dpiX = 96.0f;
bmpprops.dpiY = 96.0f;
bmpprops.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
bmpprops.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
//创建一张空的位图
pRT->CreateBitmap(size, bmpprops, m_pBmp.ReleaseAndGetAddressOf());
m_pDCompSurface->EndDraw();}
D2D1_RECT_U rc = {0, 0, nWidth, nHeight};
//将纹理上的数据拷贝到位图
pBmp->CopyFromMemory(&rc, mappedResource.pData, mappedResource.RowPitch);
m_pd3dDeviceContex->Unmap(pTempTex.Get(), 0);
3.利用ID2D1Bitmap上屏
POINT offset = {0, 0};
ComPtr<ID2D1DeviceContext> dc;
//返回d2d设备上下文
m_pDCompSurface->BeginDraw(nullptr, IID_PPV_ARGS(&dc), &offset);
if(dc)
{
D2D1_RECT_F rcBmp = {0, 0, m_width, m_height};
//2d画图
dc->DrawBitmap(m_pBmp.Get(), rcBmp);
}
m_pDCompSurface->EndDraw();
//提交命令,合成图像
m_pDCompDevice->Commit();