正如标题所示,我试图使用DirectX捕获Windows桌面并将结果显示为虚幻中的纹理。但是,生成的纹理是不正确的,因为看起来沿X轴的像素始终重复出现。
下面的代码(成功编译并在UE 4.20 / VS 2017中运行)中捕获了捕获桌面并将其转移到虚幻纹理的基本过程是:
此外,将像素值硬编码到数组中,然后使用Memcpy到Unreal纹理缓冲区中会产生正确的输出。这使我相信问题出在纹理之间的转换,或者首先是如何捕获桌面。任何帮助将不胜感激!
桌面捕获代码:
IDXGIResource* resource = nullptr;
const UINT timeout = 0; // ms
// acquire current frame of desktop
HRESULT resultAcquire = CurrentState.g_desks[iDesk].g_deskDupl->AcquireNextFrame(timeout, &CurrentState.g_desks[iDesk].g_frameInfo, &resource);
if (resultAcquire != S_OK)
{
g_needReinit++;
return;
}
CurrentState.g_desks[iDesk].g_isPointerVisible = (CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Visible == TRUE);
CurrentState.g_desks[iDesk].g_pointerX = CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Position.x;
CurrentState.g_desks[iDesk].g_pointerY = CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Position.y;
// check if resource was correctly acquired
ID3D11Texture2D* texture;
HRESULT resultQuery = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
resource->Release();
if (resultQuery != S_OK)
{
g_needReinit++;
return;
}
HRESULT hr;
// get context from device
m_Device->GetImmediateContext(&m_DeviceContext);
//Description for retrieved texture
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
switch (desc.Format) {
case DXGI_FORMAT_R8G8B8A8_UNORM:
std::cout << "Good Format";
break;
case DXGI_FORMAT_B8G8R8A8_UNORM:
std::cout << "Good Format";
break;
default:
std::cout << "Bad Format";
}
// set description for the retrieved texture
D3D11_TEXTURE2D_DESC desc2;
desc2.Width = desc.Width;
desc2.Height = desc.Height;
desc2.MipLevels = desc.MipLevels;
desc2.ArraySize = desc.ArraySize;
desc2.Format = desc.Format;
desc2.SampleDesc = desc.SampleDesc;
desc2.Usage = D3D11_USAGE_STAGING;
desc2.BindFlags = 0;
desc2.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc2.MiscFlags = 0;
// create staging texture
ID3D11Texture2D* stagingTexture;
hr = m_Device->CreateTexture2D(&desc2, nullptr, &stagingTexture);
if (FAILED(hr)) {
std::cout << "Failed";
}
// copy the texture to a staging resource
m_DeviceContext->CopyResource(stagingTexture, texture);
D3D11_MAPPED_SUBRESOURCE mapInfo;
hr = m_DeviceContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mapInfo);
if (FAILED(hr)) {
std::cout << "Failed";
}
//Use D3D11_MAPPED_SUBRESOURCE to get pointer + size of data
FTexture2DMipMap& Mip = CurrentState.g_desks[iDesk].g_texture->PlatformData->Mips[0];
// memcpy into buffer for unreal
uint8 * Data = (uint8*)Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(Data, (uint8*)mapInfo.pData, mapInfo.RowPitch * desc2.Height);
Mip.BulkData.Unlock();
// release staging texture and frame
m_DeviceContext->Unmap(stagingTexture, 0);
CurrentState.g_desks[0].g_texture->UpdateResource();
CurrentState.g_desks[iDesk].g_deskDupl->ReleaseFrame();
}
桌面捕获初始化代码:
void DeskInfo::DesktopCapturePlugin_Initialize() {
g_needReinit = 0;
IDXGIFactory1* factory;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
IDXGIAdapter1* adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
IDXGIOutput* output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); j++)
{
DXGI_OUTPUT_DESC outputDesc;
output->GetDesc(&outputDesc);
MONITORINFOEX monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(outputDesc.Monitor, &monitorInfo);
// Maybe in future add a function to identify the primary monitor.
if (monitorInfo.dwFlags == MONITORINFOF_PRIMARY)
{
int iDesk = DeskAdd();
CurrentState.g_desks[iDesk].g_width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
CurrentState.g_desks[iDesk].g_height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
//TODO: Hacky
Width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
Height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
// Feature levels supported
D3D_FEATURE_LEVEL FeatureLevels[] =
{
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;
HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, FeatureLevels, NumFeatureLevels,
D3D11_SDK_VERSION, &m_Device, &FeatureLevel, &m_DeviceContext);
if (SUCCEEDED(hr))
{
// Device creation succeeded, no need to loop anymore
IDXGIOutput1* output1;
output1 = reinterpret_cast<IDXGIOutput1*>(output);
output1->DuplicateOutput(m_Device, &CurrentState.g_desks[iDesk].g_deskDupl);
break;
}
}
output->Release();
}
adapter->Release();
}
factory->Release();
}