#include "pch.h"
#include "CDxgiCaptureImpl.h"
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#define SAFE_RELEASE(obj) if(obj) obj->Release();obj = NULL;
CDxgiCaptureImpl::CDxgiCaptureImpl(BOOL bUseShareTexture)
{
m_bUseShareTexture = bUseShareTexture;
}
CDxgiCaptureImpl::~CDxgiCaptureImpl()
{
}
TDxgiAdapterOutput CDxgiCaptureImpl::get(wstring strDeviceName)
{
IDXGIFactory1* pFactory1 = NULL;
TDxgiAdapterOutput dxgiOutput = { NULL };
do
{
bool bFind = false;
int i = 0;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory1));
if (FAILED(hr))
{
break;
}
for (;;++i)
{
IDXGIAdapter1* pAdapter1 = nullptr;
hr = pFactory1->EnumAdapters1(i, &pAdapter1);//枚举显卡设备
if (hr == DXGI_ERROR_NOT_FOUND)//枚举结束
{
break;
}
if (FAILED(hr))//枚举失败退出
{
break;
}
UINT j = 0;
for (;; ++j)
{
IDXGIOutput* pOutput = nullptr;
HRESULT hr = pAdapter1->EnumOutputs(j, &pOutput);
if (hr == DXGI_ERROR_NOT_FOUND)//枚举结束
{
break;
}
if (FAILED(hr))//枚举失败
{
SAFE_RELEASE(pAdapter1)
break;
}
DXGI_OUTPUT_DESC outdesc;
pOutput->GetDesc(&outdesc);
if ((strDeviceName.length() != 0) && strDeviceName.compare(outdesc.DeviceName) != 0)//判断要捕获的显示器名称已 枚举的是否一致
{
SAFE_RELEASE(pOutput)
}
else
{
dxgiOutput.pAdapter = pAdapter1;
dxgiOutput.pOutput = pOutput;
bFind = true;
break;
}
}
if (bFind)//已经找到匹配的显示器设备
{
break;
}
else
{
SAFE_RELEASE(pAdapter1)
}
}
SAFE_RELEASE(pFactory1)
} while (false);
return dxgiOutput;
}
BOOL CDxgiCaptureImpl::InitDxgiCapture(TDxgiAdapterOutput dxgiobj)
{
BOOL bRet = FALSE;
do
{
HRESULT hr = 0;
D3D_FEATURE_LEVEL FeatureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_1
};
UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
D3D_FEATURE_LEVEL FeatureLevel;
for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumFeatureLevels; ++DriverTypeIndex)
{
FeatureLevel = FeatureLevels[DriverTypeIndex];
hr = D3D11CreateDevice(dxgiobj.pAdapter,
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
0,
0,
0,
D3D11_SDK_VERSION,
&m_pD3D11Device,
&FeatureLevel,
&m_pD3D11Context);
if (SUCCEEDED(hr))
break;
}
if (FAILED(hr))
{
break;
}
if (FAILED(dxgiobj.pOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(&m_pDxgiOutput))))
{
break;
}
SAFE_RELEASE(dxgiobj.pOutput);//对象用到提前释放
hr = m_pDxgiOutput->DuplicateOutput(m_pD3D11Device, &m_pDeskDupl);//获取桌面重复接口
if (FAILED(hr))
{
SAFE_RELEASE(m_pDxgiOutput);
break;
}
if (!CreateD3D11Texture())
{
SAFE_RELEASE(m_pDxgiOutput);
break;
}
bRet = TRUE;
} while (false);
SAFE_RELEASE(dxgiobj.pAdapter);
SAFE_RELEASE(dxgiobj.pOutput);
return bRet;
}
BOOL CDxgiCaptureImpl::CreateD3D11Texture()
{
DXGI_OUTDUPL_DESC outdupldesc;
m_pDeskDupl->GetDesc(&outdupldesc);
D3D11_TEXTURE2D_DESC desc = {0};
m_nScreenHeight = desc.Height = outdupldesc.ModeDesc.Height;
desc.Format = outdupldesc.ModeDesc.Format;
m_nScreenWidth = desc.Width = outdupldesc.ModeDesc.Width;
desc.SampleDesc.Count = 1;
desc.MipLevels = 1;
desc.ArraySize = 1;
if (m_bUseShareTexture)
{
//使用共享纹理方式
IDXGIResource *pDxgiRes = NULL;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
if (FAILED(m_pD3D11Device->CreateTexture2D(&desc, NULL, &m_pShareTexture))) {
return FALSE;
}
if (FAILED(m_pShareTexture->QueryInterface(__uuidof(IDXGIResource), (void **)&pDxgiRes))) {
SAFE_RELEASE(m_pShareTexture)
return FALSE;
}
if (FAILED(pDxgiRes->GetSharedHandle(&m_hShareHanle))) {
SAFE_RELEASE(pDxgiRes)
SAFE_RELEASE(m_pShareTexture)
return FALSE;
}
SAFE_RELEASE(pDxgiRes)
}
else
{
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
desc.MiscFlags = 0;
if (FAILED(m_pD3D11Device->CreateTexture2D(&desc, NULL, &m_pCpuTexture)))
return FALSE;
}
return TRUE;
}
BOOL CDxgiCaptureImpl::CaptureScreen(ID3D11Texture2D ** pTex2D, void **pVideoData, INT &nWidthPitch)
{
*pVideoData = NULL;
nWidthPitch = 0;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
ZeroMemory(&frameInfo, sizeof(frameInfo));
m_pDeskDupl->ReleaseFrame();
HRESULT hr = m_pDeskDupl->AcquireNextFrame(16, &frameInfo, &m_pDesktopResource);
if (FAILED(hr))
{
switch (hr)
{
case DXGI_ERROR_WAIT_TIMEOUT:
SAFE_RELEASE(m_pDesktopResource)
return TRUE;
case DXGI_ERROR_ACCESS_LOST:
{
if (m_pDeskDupl)
{
m_pDeskDupl->ReleaseFrame();
SAFE_RELEASE(m_pDeskDupl)
}
if (m_pDxgiOutput == NULL)
{
return FALSE;
}
if (FAILED(m_pDxgiOutput->DuplicateOutput(m_pD3D11Device, &m_pDeskDupl)))
{
return FALSE;
}
hr = m_pDeskDupl->AcquireNextFrame(16, &frameInfo, &m_pDesktopResource);
if (FAILED(hr))
{
SAFE_RELEASE(m_pDesktopResource)
m_pDeskDupl->ReleaseFrame();
if (hr == DXGI_ERROR_WAIT_TIMEOUT)
{
return TRUE;
}
return FALSE;
}
}
break;
case DXGI_ERROR_INVALID_CALL:
default:
SAFE_RELEASE(m_pDesktopResource)
return FALSE;
break;
}
}
//可能只是屏幕鼠标样式更改,屏幕数据并未变化
if (frameInfo.AccumulatedFrames == 0 || frameInfo.LastPresentTime.QuadPart == 0)
{
SAFE_RELEASE(m_pDesktopResource)
return TRUE;
}
if (FAILED(m_pDesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)pTex2D)))
{
SAFE_RELEASE(m_pDesktopResource)
return FALSE;
}
if (m_bUseShareTexture)
{
m_pD3D11Context->CopyResource(m_pShareTexture, *pTex2D);
(*pTex2D)->Release();
}else
{
m_pD3D11Context->CopyResource(m_pCpuTexture, *pTex2D);
SAFE_RELEASE((*pTex2D));
if (FAILED(m_pCpuTexture->QueryInterface(__uuidof(IDXGISurface), (void**)(&m_pDxgiSurf))))
{
SAFE_RELEASE(m_pDesktopResource)
return FALSE;
}
DXGI_MAPPED_RECT mappedRect;
hr = m_pDxgiSurf->Map(&mappedRect, DXGI_MAP_READ);
if (SUCCEEDED(hr))
{
nWidthPitch = mappedRect.Pitch;
*pVideoData = mappedRect.pBits;
}
else
{
SAFE_RELEASE(m_pDxgiSurf)
}
}
SAFE_RELEASE(m_pDesktopResource)
return TRUE;
}
void CDxgiCaptureImpl::ReleaseFrame()
{
if (m_pDxgiSurf)
{
m_pDxgiSurf->Unmap();
SAFE_RELEASE(m_pDxgiSurf)
}
}
int CDxgiCaptureImpl::getWidth()
{
return m_nScreenWidth;
}
int CDxgiCaptureImpl::getHeight()
{
return m_nScreenHeight;
}
BOOL CDxgiCaptureImpl::IsShareTexturCap()
{
return m_bUseShareTexture;
}
void CDxgiCaptureImpl::UnInitDxgiCapture()
{
SAFE_RELEASE(m_pDxgiSurf);
SAFE_RELEASE(m_pDxgiOutput);
SAFE_RELEASE(m_pDeskDupl);
SAFE_RELEASE(m_pD3D11Device);
SAFE_RELEASE(m_pD3D11Context);
SAFE_RELEASE(m_pShareTexture);
SAFE_RELEASE(m_pCpuTexture);
m_hShareHanle = NULL;
}
Window C++ DXGI视频捕获源码(包含了共享纹理/cpu直接拿RGBA数据)
5星 · 超过95%的资源 需积分: 0 196 浏览量
更新于2024-02-21
2
收藏 6KB 7Z 举报
在Windows平台上进行C++开发时,DXGI(DirectX Graphics Infrastructure)是一个强大的工具,它提供了与Direct3D 11接口交互的能力,包括视频捕获功能。本项目提供的"Window C++ DXGI视频捕获源码"是实现高效视频捕获的一个实例,特别强调了共享纹理和CPU直接访问RGBA数据的能力,这在实时处理或高性能应用中非常关键。
我们要理解D3D11共享纹理的概念。在Direct3D中,纹理可以被多个设备或者上下文共享,以提高效率。共享纹理允许GPU之间或者GPU与CPU之间直接交换数据,减少了数据在不同硬件之间传输的开销。在这个项目中,通过D3D11的ID3D11Texture2D接口的特性,我们可以创建一个可以被GPU和CPU同时访问的纹理,这样在进行视频捕获时,可以避免GPU到CPU再到颜色空间转换的冗余步骤,显著降低了延迟,提高了整体性能。
该源码支持将捕获的视频帧拷贝到CPU,以RGB数据的形式。在许多应用中,我们可能需要对视频帧进行进一步的处理,例如图像分析、机器学习模型输入等,这时就需要将GPU上的纹理数据复制到CPU内存。通常,这个过程会涉及复杂的同步机制和数据转换,但通过优化的代码,这个项目能够快速地完成这个任务,确保了高效的数据流动。
再者,该项目还支持捕获特定显示器的视频流。在多显示器环境中,选择性地捕获某个显示器的输出是非常实用的功能。这可能涉及到DXGI的SwapChain接口,通过设置SwapChain的输出目标,我们可以指定要捕获的显示器。
在实际使用这个源码时,开发者需要注意以下几个方面:
1. **设备创建与上下文共享**:正确配置Direct3D 11设备和上下文,确保它们支持纹理共享。
2. **交换链创建**:根据需求创建合适的交换链,指定目标显示器,以便捕获其输出。
3. **共享纹理的创建与管理**:创建并维护共享纹理,确保在GPU和CPU之间安全地交换数据。
4. **同步机制**:由于GPU和CPU可能会并发操作共享纹理,必须使用适当的同步机制(如 fences 或 events)来防止数据竞争。
5. **数据拷贝**:优化从GPU到CPU的数据拷贝过程,减少延迟。
6. **颜色空间转换**:如果需要,进行适当的色彩空间转换,如从硬件默认的色彩空间转换为sRGB或其他格式。
对于初学者或不熟悉DXGI和Direct3D的开发者,理解并运用这些技术可能会有一定的挑战。因此,阅读和研究这个源码会是一个很好的学习机会,不仅可以深入理解GPU-CPU数据交换的细节,还可以了解到如何利用DXGI进行视频捕获,这对于开发图形密集型应用或者游戏开发来说,都是非常宝贵的经验。在实际项目中,可以根据具体需求调整和扩展这个源码,以满足更复杂的需求。
独行者717
- 粉丝: 357
- 资源: 11