检索要通过网络发送的 ID3D11Texture2D 数据
Retrieving ID3D11Texture2D data to be sent over network
我正在修改桌面复制 api 示例 kindly provided by Microsoft 以捕获屏幕并通过网络将更新发送到我的应用程序。我知道如何实际发送数据;我的问题是从 ID3D11Texture2D 对象获取数据。
ID3D11Texture2D* m_AcquiredDesktopImage;
IDXGIResource* desktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
// Get new frame
HRESULT hr = m_DeskDupl->AcquireNextFrame(500, &FrameInfo, &desktopResource);
// QI for IDXGIResource
hr = desktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&m_AcquiredDesktopImage));
此时,我认为屏幕更新在 m_AcquiredDesktopImage
。我需要通过网络传输这些数据(尽可能高效)。
This answer 似乎是在正确的轨道上,但我是 Windows 编程的新手,所以我需要一些额外的帮助。
这是我能想到的唯一利用 IDXGIObject::GetPrivateData
的解决方案
私人数据根本不是您要找的。它们只是在这里将自定义值附加到 d3d 对象。
一旦你有了需要从中读回图像的 ID3D11Texture2D
对象,你需要从 ID3D11Device
在暂存内存池中创建第二个对象(获取原始描述,更改池,并删除绑定)。
然后,您需要使用 ID3D11DeviceContext
将纹理复制到使用 CopyResource
的暂存纹理。然后你可以使用上下文 Map
和 Unmap
api 来读取图像。
我有一个很好的 link 可以做到这一点.. 寻找方法 SaveTextureToBmp
[...]
// map the texture
ComPtr<ID3D11Texture2D> mappedTexture;
D3D11_MAPPED_SUBRESOURCE mapInfo;
mapInfo.RowPitch;
hr = d3dContext->Map(
Texture,
0, // Subresource
D3D11_MAP_READ,
0, // MapFlags
&mapInfo);
if (FAILED(hr)) {
// If we failed to map the texture, copy it to a staging resource
if (hr == E_INVALIDARG) {
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;
ComPtr<ID3D11Texture2D> stagingTexture;
hr = d3dDevice->CreateTexture2D(&desc2, nullptr, &stagingTexture);
if (FAILED(hr)) {
throw MyException::Make(hr, L"Failed to create staging texture");
}
// copy the texture to a staging resource
d3dContext->CopyResource(stagingTexture.Get(), Texture);
// now, map the staging resource
hr = d3dContext->Map(
stagingTexture.Get(),
0,
D3D11_MAP_READ,
0,
&mapInfo);
if (FAILED(hr)) {
throw MyException::Make(hr, L"Failed to map staging texture");
}
mappedTexture = std::move(stagingTexture);
} else {
throw MyException::Make(hr, L"Failed to map texture.");
}
} else {
mappedTexture = Texture;
}
auto unmapResource = Finally([&] {
d3dContext->Unmap(mappedTexture.Get(), 0);
});
[...]
hr = frameEncode->WritePixels(
desc.Height,
mapInfo.RowPitch,
desc.Height * mapInfo.RowPitch,
reinterpret_cast<BYTE*>(mapInfo.pData));
if (FAILED(hr)) {
throw MyException::Make(hr, L"frameEncode->WritePixels(...) failed.");
}
我正在修改桌面复制 api 示例 kindly provided by Microsoft 以捕获屏幕并通过网络将更新发送到我的应用程序。我知道如何实际发送数据;我的问题是从 ID3D11Texture2D 对象获取数据。
ID3D11Texture2D* m_AcquiredDesktopImage;
IDXGIResource* desktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
// Get new frame
HRESULT hr = m_DeskDupl->AcquireNextFrame(500, &FrameInfo, &desktopResource);
// QI for IDXGIResource
hr = desktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&m_AcquiredDesktopImage));
此时,我认为屏幕更新在 m_AcquiredDesktopImage
。我需要通过网络传输这些数据(尽可能高效)。
This answer 似乎是在正确的轨道上,但我是 Windows 编程的新手,所以我需要一些额外的帮助。
这是我能想到的唯一利用 IDXGIObject::GetPrivateData
私人数据根本不是您要找的。它们只是在这里将自定义值附加到 d3d 对象。
一旦你有了需要从中读回图像的 ID3D11Texture2D
对象,你需要从 ID3D11Device
在暂存内存池中创建第二个对象(获取原始描述,更改池,并删除绑定)。
然后,您需要使用 ID3D11DeviceContext
将纹理复制到使用 CopyResource
的暂存纹理。然后你可以使用上下文 Map
和 Unmap
api 来读取图像。
我有一个很好的 link 可以做到这一点.. 寻找方法 SaveTextureToBmp
[...]
// map the texture
ComPtr<ID3D11Texture2D> mappedTexture;
D3D11_MAPPED_SUBRESOURCE mapInfo;
mapInfo.RowPitch;
hr = d3dContext->Map(
Texture,
0, // Subresource
D3D11_MAP_READ,
0, // MapFlags
&mapInfo);
if (FAILED(hr)) {
// If we failed to map the texture, copy it to a staging resource
if (hr == E_INVALIDARG) {
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;
ComPtr<ID3D11Texture2D> stagingTexture;
hr = d3dDevice->CreateTexture2D(&desc2, nullptr, &stagingTexture);
if (FAILED(hr)) {
throw MyException::Make(hr, L"Failed to create staging texture");
}
// copy the texture to a staging resource
d3dContext->CopyResource(stagingTexture.Get(), Texture);
// now, map the staging resource
hr = d3dContext->Map(
stagingTexture.Get(),
0,
D3D11_MAP_READ,
0,
&mapInfo);
if (FAILED(hr)) {
throw MyException::Make(hr, L"Failed to map staging texture");
}
mappedTexture = std::move(stagingTexture);
} else {
throw MyException::Make(hr, L"Failed to map texture.");
}
} else {
mappedTexture = Texture;
}
auto unmapResource = Finally([&] {
d3dContext->Unmap(mappedTexture.Get(), 0);
});
[...]
hr = frameEncode->WritePixels(
desc.Height,
mapInfo.RowPitch,
desc.Height * mapInfo.RowPitch,
reinterpret_cast<BYTE*>(mapInfo.pData));
if (FAILED(hr)) {
throw MyException::Make(hr, L"frameEncode->WritePixels(...) failed.");
}