本篇文章是本人音视频技术文章集中的开篇,之后会持续更新创作更多关于音视频的文章。望有大佬可以交流、指点。
文章主要表现形式是以实现为主,扩展知识为辅,所以一般比较长,不过也有更多实现细节以供参考。
技术简介
DXGI(Microsoft DirectX Graphics Infrastructure)是微软提供的一种可以在win8及以上系统使用的图形设备接口。它负责枚举图形适配器、枚举显示模式、选择缓冲区格式、在进程之间(例如,在应用程序和桌面窗口管理器(DWM)之间)共享资源,以及将呈现的帧传给窗口或监视器以供显示。其直接和硬件设备进行交互,具有很高的效率和性能。
Direct3D 10、Direct3D 11和Direct3D 12等都使用DXGI技术。
使用模块(库)
本篇代码中使用到了d3d11和dxgi两个dll库。
主要流程和代码
1、加载d3d11和dxgi库,并初始化d3d设备。
int DuplicationCaptor::init(const DesktopCaptureRect& rect, const int fps)
{
int err = ERROR_CODE_OK;
if (m_inited) {
return err;
}
do {
m_d3d = HELPER::SystemLib::loadSystemLib("d3d11.dll");
if (m_d3d == nullptr) {
err = ERROR_CODE_D3D_LOAD_LIB_FAILED;
break;
}
m_dxgi = HELPER::SystemLib::loadSystemLib("dxgi.dll");
if (m_dxgi == nullptr) {
err = ERROR_CODE_DXGI_LOAD_LIB_FAILED;
break;
}
err = initD3d();
HCMDR_ERROR_CODE_BREAK(err);
m_timebase = {
1, AV_TIME_BASE };
m_pixelFmt = AV_PIX_FMT_BGRA;
m_rect = rect;
m_fps = fps;
m_width = rect.right - rect.left;
m_height = rect.bottom - rect.top;
m_bufferSize = (m_width * 32 + 31) / 32 * m_height * 4;
m_buffer = new uint8_t[m_bufferSize];
m_inited = true;
} while (0);
if (err != ERROR_CODE_OK) {
LOGGER::Logger::log(LOGGER::LOG_TYPE_ERROR, "[%s] msg: %s, last error: %lu", __FUNCTION__,
HCMDR_GET_ERROR_DESC(err), GetLastError());
cleanup();
}
return err;
}
init中d3d设备初始化函数:
int DuplicationCaptor::initD3d()
{
int err = ERROR_CODE_OK;
do {
IDXGIAdapter* adapter = nullptr;
err = getAdapter(&adapter);
HCMDR_ERROR_CODE_BREAK(err);
err = createD3dDevice(adapter, &m_d3dDevice);
HCMDR_ERROR_CODE_BREAK(err);
} while (0);
return err;
}
initD3d中获取适配器函数:
int DuplicationCaptor::getAdapter(IDXGIAdapter** adapter)
{
int err = ERROR_CODE_OK;
do {
std::list<IDXGIAdapter*> adapters;
err = getAdapters(adapters);
HCMDR_ERROR_CODE_BREAK(err);
if (adapters.empty()) {
err = ERROR_CODE_DXGI_FOUND_ADAPTER_FAILED;
break;
}
for (std::list<IDXGIAdapter*>::iterator it = adapters.begin(); it != adapters.end(); it++) {
IDXGIOutput* adapterOutput = nullptr;
DXGI_ADAPTER_DESC adapterDesc = {
0 };
(*it)->GetDesc(&adapterDesc);
for (UINT i = 0; (*it)->EnumOutputs(i, &adapterOutput) != DXGI_ERROR_NOT_FOUND; i++) {
DXGI_OUTPUT_DESC outputDesc = {
0 };
RECT outputRect = {
0 };
HRESULT hr = adapterOutput->GetDesc(&outputDesc);
if (FAILED(hr)) {
continue;
}
outputRect = outputDesc.DesktopCoordinates;
// The target area is within the selected area
if (m_rect.left >= outputRect.left && m_rect.top >= outputRect.top &&
m_rect.right <= outputRect.right && m_rect.bottom <= outputRect.bottom) {
break;
}
}
if (err == ERROR_CODE_OK) {
*adapter = *it;
break;
}
}
} while (0);
return err;
}
getAdapter中获取适配器列表函数:
int DuplicationCaptor::getAdapters(std::list<IDXGIAdapter*>& adapters)
{
int err = ERROR_CODE_OK;
do {
DXGI_CREATE_FACTORY1 createFactory1 = (DXGI_CREATE_FACTORY1)GetProcAddress(m_dxgi, "CreateDXGIFactory1");
if (createFactory1 == nullptr) {
err = ERROR_CODE_DXGI_GET_PROC_FAILED;
break;
}
IDXGIFactory1* factory1 = nullptr;
HRESULT hr = createFactory1(__uuidof(IDXGIFactory1), &factory1);
if (FAILED(hr)) {
err = ERROR_CODE_DXGI_GET_FACTORY_FAILED;
break;
}
IDXGIAdapter* adapter = nullptr;
adapters.clear();
for (UINT i = 0; factory1->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) {
if (adapter != nullptr