187 lines
5.2 KiB
C++
187 lines
5.2 KiB
C++
|
#include "DXGIDuplicator.h"
|
||
|
#include "Utils/Utils.h"
|
||
|
DXGIDuplicator::DXGIDuplicator()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
DXGIDuplicator::~DXGIDuplicator()
|
||
|
{
|
||
|
if (duplication_)
|
||
|
{
|
||
|
duplication_->Release();
|
||
|
}
|
||
|
if (device_)
|
||
|
{
|
||
|
device_->Release();
|
||
|
}
|
||
|
if (deviceContext_)
|
||
|
{
|
||
|
deviceContext_->Release();
|
||
|
}
|
||
|
}
|
||
|
bool DXGIDuplicator::InitD3D11Device(ID3D11Device* g_pd3dDevice, ID3D11DeviceContext* g_pImmediateContext)
|
||
|
{
|
||
|
device_ = g_pd3dDevice;
|
||
|
deviceContext_ = g_pImmediateContext;
|
||
|
return true;
|
||
|
}
|
||
|
bool DXGIDuplicator::InitDuplication()
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
IDXGIDevice* dxgiDevice = nullptr;
|
||
|
hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
IDXGIAdapter* dxgiAdapter = nullptr;
|
||
|
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
|
||
|
dxgiDevice->Release();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
UINT output = 0;
|
||
|
IDXGIOutput* dxgiOutput = nullptr;
|
||
|
while (true)
|
||
|
{
|
||
|
hr = dxgiAdapter->EnumOutputs(output++, &dxgiOutput);
|
||
|
if (hr == DXGI_ERROR_NOT_FOUND)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DXGI_OUTPUT_DESC desc;
|
||
|
dxgiOutput->GetDesc(&desc);
|
||
|
int width = desc.DesktopCoordinates.right - desc.DesktopCoordinates.left;
|
||
|
int height = desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
dxgiAdapter->Release();
|
||
|
|
||
|
IDXGIOutput1* dxgiOutput1 = nullptr;
|
||
|
hr = dxgiOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(&dxgiOutput1));
|
||
|
dxgiOutput->Release();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
hr = dxgiOutput1->DuplicateOutput(device_, &duplication_);
|
||
|
dxgiOutput1->Release();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
#include <dwmapi.h>
|
||
|
HRESULT DXGIDuplicator::GetDesktopFrame(ID3D11Texture2D*& texture)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||
|
IDXGIResource* resource = NULL;
|
||
|
ID3D11Texture2D* pSrcTexture = NULL;
|
||
|
FreeFrame();
|
||
|
hr = duplication_->AcquireNextFrame(INFINITE, &frameInfo, &resource);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
frameRef += 1;
|
||
|
hr = resource->QueryInterface(IID_PPV_ARGS(&texture));
|
||
|
resource->Release();
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
if (frameInfo.LastPresentTime.QuadPart == 0)
|
||
|
return DXGI_ERROR_WAIT_TIMEOUT;
|
||
|
return hr;
|
||
|
}
|
||
|
ID3D11Texture2D* DXGIDuplicator::ConvertFormat(ID3D11Texture2D* pSrcTexture, DXGI_FORMAT fmt)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
ID3D11Texture2D* pDestTexture = NULL;
|
||
|
|
||
|
D3D11_TEXTURE2D_DESC desc;
|
||
|
pSrcTexture->GetDesc(&desc);
|
||
|
desc.Format = fmt;
|
||
|
desc.Usage = D3D11_USAGE_STAGING;
|
||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
|
||
|
desc.BindFlags = 0;
|
||
|
desc.MiscFlags = 0;
|
||
|
desc.MipLevels = 1;
|
||
|
desc.ArraySize = 1;
|
||
|
desc.SampleDesc.Count = 1;
|
||
|
desc.SampleDesc.Quality = 0;
|
||
|
device_->CreateTexture2D(&desc, NULL, &pDestTexture);
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
deviceContext_->CopyResource(pDestTexture, pSrcTexture);
|
||
|
return pDestTexture;
|
||
|
}
|
||
|
void* DXGIDuplicator::MapBuffer(ID3D11Texture2D* texture2D)
|
||
|
{
|
||
|
D3D11_MAPPED_SUBRESOURCE mappedResource{};
|
||
|
HRESULT hr = this->deviceContext_->Map(texture2D, 0, D3D11_MAP_READ, 0, &mappedResource);
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
return mappedResource.pData;
|
||
|
}
|
||
|
void DXGIDuplicator::UnMapBuffer(ID3D11Texture2D* texture2D)
|
||
|
{
|
||
|
this->deviceContext_->Unmap(texture2D, 0);
|
||
|
}
|
||
|
std::vector<uint8_t> DXGIDuplicator::GenerateBitmapFile(ID3D11Texture2D* texture2D)
|
||
|
{
|
||
|
D3D11_TEXTURE2D_DESC desc{};
|
||
|
texture2D->GetDesc(&desc);
|
||
|
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
||
|
HRESULT hr = this->deviceContext_->Map(texture2D, 0, D3D11_MAP_READ, 0, &mappedResource);
|
||
|
if (FAILED(hr))
|
||
|
return std::vector<uint8_t>();
|
||
|
|
||
|
size_t bmpSize = desc.Width * desc.Height * 4;
|
||
|
std::vector<uint8_t> result(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmpSize, 0);
|
||
|
|
||
|
BITMAPFILEHEADER* bmpHeader = (BITMAPFILEHEADER*)(&result[0]);
|
||
|
BITMAPINFOHEADER* bmiHeader = (BITMAPINFOHEADER*)(&result[0] + sizeof(BITMAPFILEHEADER));
|
||
|
|
||
|
uint8_t* rgba = (uint8_t*)(&result[0] + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
|
||
|
|
||
|
bmpHeader->bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmpSize;
|
||
|
bmpHeader->bfType = 0x4D42;
|
||
|
bmpHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||
|
bmpHeader->bfReserved1 = 0;
|
||
|
bmpHeader->bfReserved2 = 0;
|
||
|
|
||
|
bmiHeader->biSize = sizeof(BITMAPINFOHEADER);
|
||
|
bmiHeader->biWidth = desc.Width;
|
||
|
bmiHeader->biHeight = 0 - desc.Height;
|
||
|
bmiHeader->biPlanes = 1;
|
||
|
bmiHeader->biBitCount = 32;
|
||
|
bmiHeader->biCompression = 0;
|
||
|
bmiHeader->biSizeImage = bmpSize;
|
||
|
bmiHeader->biXPelsPerMeter = 0;
|
||
|
bmiHeader->biYPelsPerMeter = 0;
|
||
|
bmiHeader->biClrUsed = 0;
|
||
|
bmiHeader->biClrImportant = 0;
|
||
|
|
||
|
memcpy(rgba, mappedResource.pData, bmpSize);
|
||
|
this->deviceContext_->Unmap(texture2D, 0);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
HRESULT DXGIDuplicator::FreeFrame()
|
||
|
{
|
||
|
if (frameRef > 0)
|
||
|
{
|
||
|
frameRef -= 1;
|
||
|
return duplication_->ReleaseFrame();
|
||
|
}
|
||
|
return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
|
||
|
}
|