增加扩展屏的框架
This commit is contained in:
243
demo/windows_sender/IddBridge.cpp
Normal file
243
demo/windows_sender/IddBridge.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
#include "IddBridge.h"
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
IddBridge::IddBridge() = default;
|
||||
|
||||
IddBridge::~IddBridge() {
|
||||
if (frame_acquired_) {
|
||||
ReleaseFrame();
|
||||
}
|
||||
if (shared_) {
|
||||
UnmapViewOfFile(shared_);
|
||||
shared_ = nullptr;
|
||||
}
|
||||
if (hMap_) {
|
||||
CloseHandle(hMap_);
|
||||
hMap_ = nullptr;
|
||||
}
|
||||
if (hReadyEvent_) {
|
||||
CloseHandle(hReadyEvent_);
|
||||
hReadyEvent_ = nullptr;
|
||||
}
|
||||
if (hConsumedEvent_) {
|
||||
CloseHandle(hConsumedEvent_);
|
||||
hConsumedEvent_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool IddBridge::Initialize() {
|
||||
D3D_FEATURE_LEVEL featureLevels[] = {
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
};
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
HRESULT hr = D3D11CreateDevice(
|
||||
nullptr,
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels,
|
||||
ARRAYSIZE(featureLevels),
|
||||
D3D11_SDK_VERSION,
|
||||
&device_,
|
||||
&featureLevel,
|
||||
&context_
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
hr = D3D11CreateDevice(
|
||||
nullptr,
|
||||
D3D_DRIVER_TYPE_WARP,
|
||||
nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels,
|
||||
ARRAYSIZE(featureLevels),
|
||||
D3D11_SDK_VERSION,
|
||||
&device_,
|
||||
&featureLevel,
|
||||
&context_
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring mapName = L"Global\\DisplayFlowIddFrame";
|
||||
std::wstring readyName = L"Global\\DisplayFlowIddReady";
|
||||
std::wstring consumedName = L"Global\\DisplayFlowIddConsumed";
|
||||
|
||||
hMap_ = OpenFileMappingW(FILE_MAP_READ, FALSE, mapName.c_str());
|
||||
if (!hMap_) {
|
||||
// Fallback to Local (Simulation mode)
|
||||
mapName = L"Local\\DisplayFlowIddFrame";
|
||||
readyName = L"Local\\DisplayFlowIddReady";
|
||||
consumedName = L"Local\\DisplayFlowIddConsumed";
|
||||
hMap_ = OpenFileMappingW(FILE_MAP_READ, FALSE, mapName.c_str());
|
||||
}
|
||||
|
||||
if (!hMap_) {
|
||||
// Create for testing; in production UMDF service should create
|
||||
shared_size_ = 64 * 1024 * 1024; // 64MB
|
||||
hMap_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)shared_size_, mapName.c_str());
|
||||
if (!hMap_) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Unknown size; assume max
|
||||
shared_size_ = 64 * 1024 * 1024;
|
||||
}
|
||||
|
||||
shared_ = (uint8_t*)MapViewOfFile(hMap_, FILE_MAP_READ, 0, 0, shared_size_);
|
||||
if (!shared_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hReadyEvent_ = OpenEventW(SYNCHRONIZE, FALSE, readyName.c_str());
|
||||
if (!hReadyEvent_) {
|
||||
hReadyEvent_ = CreateEventW(nullptr, FALSE, FALSE, readyName.c_str());
|
||||
}
|
||||
hConsumedEvent_ = OpenEventW(EVENT_MODIFY_STATE, FALSE, consumedName.c_str());
|
||||
if (!hConsumedEvent_) {
|
||||
hConsumedEvent_ = CreateEventW(nullptr, FALSE, FALSE, consumedName.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IddBridge::EnsureTexture(int width, int height) {
|
||||
if (gpuTexture_ && tex_width_ == width && tex_height_ == height) return true;
|
||||
gpuTexture_.Reset();
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = 0;
|
||||
|
||||
HRESULT hr = device_->CreateTexture2D(&desc, nullptr, &gpuTexture_);
|
||||
if (FAILED(hr)) return false;
|
||||
tex_width_ = width;
|
||||
tex_height_ = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IddBridge::CaptureFrame(ComPtr<ID3D11Texture2D>& texture) {
|
||||
if (!shared_ || !hReadyEvent_) return false;
|
||||
|
||||
DWORD wait = WaitForSingleObject(hReadyEvent_, 100);
|
||||
if (wait != WAIT_OBJECT_0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* hdr = reinterpret_cast<const IddSharedHeader*>(shared_);
|
||||
if (hdr->format != 0) {
|
||||
return false;
|
||||
}
|
||||
int w = (int)hdr->width;
|
||||
int h = (int)hdr->height;
|
||||
int stride = (int)hdr->stride;
|
||||
const uint8_t* pixels = shared_ + sizeof(IddSharedHeader);
|
||||
|
||||
if (!EnsureTexture(w, h)) return false;
|
||||
|
||||
D3D11_BOX box = {};
|
||||
box.left = 0; box.right = w;
|
||||
box.top = 0; box.bottom = h;
|
||||
box.front = 0; box.back = 1;
|
||||
|
||||
context_->UpdateSubresource(gpuTexture_.Get(), 0, nullptr, pixels, stride, 0);
|
||||
|
||||
frame_acquired_ = true;
|
||||
texture = gpuTexture_;
|
||||
|
||||
if (hConsumedEvent_) {
|
||||
SetEvent(hConsumedEvent_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IddBridge::ReleaseFrame() {
|
||||
frame_acquired_ = false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// IddProducer Implementation
|
||||
// ============================================================================
|
||||
|
||||
IddProducer::IddProducer() = default;
|
||||
|
||||
IddProducer::~IddProducer() {
|
||||
if (shared_) UnmapViewOfFile(shared_);
|
||||
if (hMap_) CloseHandle(hMap_);
|
||||
if (hReadyEvent_) CloseHandle(hReadyEvent_);
|
||||
if (hConsumedEvent_) CloseHandle(hConsumedEvent_);
|
||||
}
|
||||
|
||||
bool IddProducer::Initialize() {
|
||||
std::wstring mapName = L"Local\\DisplayFlowIddFrame";
|
||||
std::wstring readyName = L"Local\\DisplayFlowIddReady";
|
||||
std::wstring consumedName = L"Local\\DisplayFlowIddConsumed";
|
||||
|
||||
shared_size_ = 64 * 1024 * 1024; // 64MB
|
||||
|
||||
// Producer prefers Creating
|
||||
hMap_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)shared_size_, mapName.c_str());
|
||||
if (!hMap_) {
|
||||
// Maybe already exists
|
||||
hMap_ = OpenFileMappingW(FILE_MAP_WRITE, FALSE, mapName.c_str());
|
||||
if (!hMap_) return false;
|
||||
}
|
||||
|
||||
shared_ = (uint8_t*)MapViewOfFile(hMap_, FILE_MAP_WRITE, 0, 0, shared_size_);
|
||||
if (!shared_) return false;
|
||||
|
||||
hReadyEvent_ = CreateEventW(nullptr, FALSE, FALSE, readyName.c_str());
|
||||
if (!hReadyEvent_) {
|
||||
hReadyEvent_ = OpenEventW(EVENT_MODIFY_STATE, FALSE, readyName.c_str());
|
||||
if (!hReadyEvent_) return false;
|
||||
}
|
||||
|
||||
hConsumedEvent_ = CreateEventW(nullptr, FALSE, FALSE, consumedName.c_str());
|
||||
if (!hConsumedEvent_) {
|
||||
hConsumedEvent_ = OpenEventW(SYNCHRONIZE, FALSE, consumedName.c_str());
|
||||
// If failed, consumer might create it later.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IddProducer::SubmitFrame(const void* data, uint32_t width, uint32_t height, uint32_t stride) {
|
||||
if (!shared_ || !hReadyEvent_) return false;
|
||||
|
||||
// Ensure consumer created the event if we missed it
|
||||
if (!hConsumedEvent_) {
|
||||
hConsumedEvent_ = OpenEventW(SYNCHRONIZE, FALSE, L"Local\\DisplayFlowIddConsumed");
|
||||
}
|
||||
|
||||
// Optional: Wait for previous frame consumption to avoid tearing/overflow
|
||||
// if (hConsumedEvent_) WaitForSingleObject(hConsumedEvent_, 0);
|
||||
// For now, overwrite mode is faster for streaming.
|
||||
|
||||
IddSharedHeader* hdr = reinterpret_cast<IddSharedHeader*>(shared_);
|
||||
|
||||
uint32_t needed = sizeof(IddSharedHeader) + stride * height;
|
||||
if (needed > shared_size_) return false;
|
||||
|
||||
hdr->width = width;
|
||||
hdr->height = height;
|
||||
hdr->format = 0;
|
||||
hdr->stride = stride;
|
||||
hdr->timestamp = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count();
|
||||
hdr->frameId = ++frameId_;
|
||||
hdr->dataSize = stride * height;
|
||||
|
||||
std::memcpy(shared_ + sizeof(IddSharedHeader), data, hdr->dataSize);
|
||||
|
||||
SetEvent(hReadyEvent_);
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user