Вот журналы, которые я получаю: < /p>
[32632] [INFO] Callback successfully invoked.
[32632] [INFO] Callback successfully invoked.
[32632] [INFO] Callback successfully invoked.
[32632] [INFO] Callback successfully invoked.
[32632] [INFO] Callback successfully invoked.
[32632] [CRITICAL] Capture session unexpectedly removed from map!
[32632] [WARNING] Capture session missing in FrameArrived!
[32632] [ERROR] Capture session lost unexpectedly
[32632] [WARNING] Capture session missing in FrameArrived!
< /code>
Это действительно случайно, это обычно происходит через несколько секунд, но захват может работать совершенно нормально в течение примерно до 30 секунд до того, как карта внезапно не обнаружил объекта капсунсии на карте.#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#include
#include
#include
#include
#include //
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include // For WinRT DispatcherQueue
#include // For DispatcherQueue
#include // For std::async
#include
#include
#include // Ensure this is included
#include
#include
#include
//
using namespace Microsoft::WRL;
using namespace winrt;
//
struct CaptureSession {
CaptureSession(
HWND hwnd,
ComPtr dev, ComPtr ctx,
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool fp,
winrt::Windows::Graphics::Capture::GraphicsCaptureSession sess,
winrt::Windows::Graphics::Capture::GraphicsCaptureItem it)
: hwnd(hwnd), d3dDevice(dev), d3dContext(ctx), framePool(fp), session(sess), item(it) {
}
HWND hwnd; // Store the HWND
ComPtr d3dDevice;
ComPtr d3dContext;
ComPtr frameTexture;
ComPtr stagingTexture;
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool framePool;
winrt::Windows::Graphics::Capture::GraphicsCaptureSession session;
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item;
};
//
struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
IDirect3DDxgiInterfaceAccess : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetInterface(
REFIID riid,
void** ppvObject
) = 0;
};
//
struct HWNDHash {
std::size_t operator()(HWND hwnd) const {
return std::hash{}(reinterpret_cast(hwnd));
}
};
//
typedef void (*FrameCallback)(const void*, size_t, int, int);
FrameCallback g_FrameCallback = nullptr;
//
std::unordered_map captureSessions;
std::unordered_map frameCallbacks;
std::shared_mutex captureMutex;
//
HRESULT InitializeD3D11(ComPtr& outDevice, ComPtr& outContext) {
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#ifdef _DEBUG
flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 };
HRESULT hr = D3D11CreateDevice(
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags,
featureLevels, _countof(featureLevels),
D3D11_SDK_VERSION, &outDevice, nullptr, &outContext
);
return hr;
}
extern "C" __declspec(dllexport) void RegisterFrameCallback(const char* sessionKey, FrameCallback callback) {
std::lock_guard lock(captureMutex);
OutputDebugStringA("[INFO] Registering callback for session key: ");
OutputDebugStringA(sessionKey);
OutputDebugStringA("\n");
frameCallbacks[sessionKey] = callback;
if (frameCallbacks.find(sessionKey) != frameCallbacks.end() && frameCallbacks[sessionKey].has_value()) {
OutputDebugStringA("[INFO] Callback successfully registered!\n");
}
else {
OutputDebugStringA("[ERROR] Failed to register callback!\n");
}
}
void CALLBACK OnFrameArrived(const char* sessionKey, winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool sender, winrt::Windows::Foundation::IInspectable const&) {
try {
std::shared_ptr session;
{
std::shared_lock lock(captureMutex);
auto it = captureSessions.find(sessionKey);
if (it == captureSessions.end() || !it->second) {
OutputDebugStringA("[ERROR] Capture session DISAPPEARED before processing FrameArrived! Possible DirectX failure.\n");
return;
}
session = it->second;
}
winrt::Windows::Graphics::Capture::Direct3D11CaptureFrame frame = sender.TryGetNextFrame();
if (!frame) {
OutputDebugStringA("[ERROR] Failed to retrieve frame! Possible DirectX failure or session lost.\n");
return;
}
ComPtr frameTexture;
IUnknown* rawUnknown = winrt::get_unknown(frame.Surface());
if (!rawUnknown) {
OutputDebugStringA("[ERROR] Failed to retrieve frame surface!\n");
return;
}
ComPtr dxgiAccess;
HRESULT hr = rawUnknown->QueryInterface(__uuidof(IDirect3DDxgiInterfaceAccess), reinterpret_cast(dxgiAccess.GetAddressOf()));
if (FAILED(hr)) {
OutputDebugStringA("[ERROR] Failed to get DXGI interface from frame surface!\n");
return;
}
hr = dxgiAccess->GetInterface(__uuidof(ID3D11Texture2D), reinterpret_cast(frameTexture.GetAddressOf()));
if (FAILED(hr)) {
OutputDebugStringA("[ERROR] Failed to get ID3D11Texture2D interface!\n");
return;
}
//
D3D11_TEXTURE2D_DESC desc;
frameTexture->GetDesc(&desc);
UINT captureWidth = desc.Width;
UINT captureHeight = desc.Height;
//
if (!session->stagingTexture || desc.Width != captureWidth || desc.Height != captureHeight) {
OutputDebugStringA("[INFO] Creating new staging texture due to resolution change.\n");
D3D11_TEXTURE2D_DESC stagingDesc = desc;
stagingDesc.Usage = D3D11_USAGE_STAGING;
stagingDesc.BindFlags = 0;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.MiscFlags = 0;
session->stagingTexture.Reset();
hr = session->d3dDevice->CreateTexture2D(&stagingDesc, nullptr, &session->stagingTexture);
if (FAILED(hr)) {
OutputDebugStringA("[ERROR] Failed to create staging texture! Possible DirectX device loss.\n");
return;
}
}
//
session->d3dContext->CopyResource(session->stagingTexture.Get(), frameTexture.Get());
//
D3D11_MAPPED_SUBRESOURCE mappedResource;
hr = session->d3dContext->Map(session->stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mappedResource);
if (FAILED(hr)) {
OutputDebugStringA("[ERROR] Failed to map staging texture! Possible GPU memory issue.\n");
return;
}
//
size_t bufferSize = captureWidth * captureHeight * 4;
std::vector frameBuffer(bufferSize);
for (UINT y = 0; y < captureHeight; ++y) {
memcpy(frameBuffer.data() + (y * captureWidth * 4),
static_cast(mappedResource.pData) + (y * mappedResource.RowPitch),
captureWidth * 4);
}
session->d3dContext->Unmap(session->stagingTexture.Get(), 0);
//
FrameCallback callback = nullptr;
{
std::shared_lock lock(captureMutex);
auto callbackIt = frameCallbacks.find(sessionKey);
if (callbackIt == frameCallbacks.end() || !callbackIt->second) {
OutputDebugStringA("[WARNING] No callback found for session!\n");
return;
}
callback = callbackIt->second.value();
}
//
if (callback) {
try {
callback(static_cast(frameBuffer.data()), frameBuffer.size(), captureWidth, captureHeight);
OutputDebugStringA("[INFO] Callback successfully invoked.\n");
}
catch (const std::exception& e) {
OutputDebugStringA("[ERROR] Exception inside callback: ");
OutputDebugStringA(e.what());
OutputDebugStringA("\n");
}
catch (...) {
OutputDebugStringA("[ERROR] Unknown exception inside callback!\n");
}
}
}
catch (const std::exception& e) {
OutputDebugStringA("[CRITICAL] Exception in FrameArrived: ");
OutputDebugStringA(e.what());
OutputDebugStringA("\n");
}
catch (...) {
OutputDebugStringA("[CRITICAL] Unknown exception in FrameArrived!\n");
}
}
//
static std::optional g_dispatcherQueueController;
void EnsureDispatcherQueue() {
OutputDebugStringA("555!\n");
static std::once_flag flag;
OutputDebugStringA("777!\n");
std::call_once(flag, []() {
try {
OutputDebugStringA("[INFO] Initializing WinRT apartment...\n");
winrt::init_apartment(winrt::apartment_type::multi_threaded);
OutputDebugStringA("[INFO] WinRT apartment initialized successfully.\n");
}
catch (const std::exception& e) {
OutputDebugStringA("[ERROR] Failed to initialize WinRT apartment: ");
OutputDebugStringA(e.what());
OutputDebugStringA("\n");
}
catch (...) {
OutputDebugStringA("[ERROR] Failed to initialize WinRT apartment: Unknown error.\n");
}
});
OutputDebugStringA("[INFO] 888\n");
//
using namespace winrt::Windows::System;
OutputDebugStringA("[INFO] 22\n");
//
DispatcherQueue currentQueue = DispatcherQueue::GetForCurrentThread();
if (currentQueue) {
OutputDebugStringA("[INFO] DispatcherQueue already exists for the current thread.\n");
return;
}
OutputDebugStringA("[INFO] 33\n");
//
if (g_dispatcherQueueController.has_value()) {
return;
}
//
DispatcherQueueOptions options{
sizeof(DispatcherQueueOptions),
DQTYPE_THREAD_CURRENT,
DQTAT_COM_STA
};
ABI::Windows::System::IDispatcherQueueController* rawQueueController = nullptr;
HRESULT hr = CreateDispatcherQueueController(options, &rawQueueController);
if (FAILED(hr) || !rawQueueController) {
OutputDebugStringA("[ERROR] Failed to create DispatcherQueueController!\n");
return;
}
//
g_dispatcherQueueController.emplace(reinterpret_cast(rawQueueController));
OutputDebugStringA("[INFO] DispatcherQueueController created successfully.\n");
}
//
extern "C" __declspec(dllexport) bool StartCapture(const char* sessionKey, HWND hwnd) {
std::unique_lock lock(captureMutex);
// Check if the session already exists
if (captureSessions.find(sessionKey) != captureSessions.end()) {
OutputDebugStringA("[INFO] Capture already running for this session key!\n");
return true;
}
// Use a shared_ptr to keep the session alive
auto captureSession = std::make_shared(
hwnd, nullptr, nullptr, nullptr, nullptr, nullptr);
//
static std::vector sessionHolder;
sessionHolder.push_back(captureSession);
// Launch a new thread with its own DispatcherQueue
std::thread([sessionKey, hwnd, captureSession]() {
captureSessions[sessionKey] = captureSession;
winrt::init_apartment(winrt::apartment_type::multi_threaded);
DispatcherQueueOptions options{ sizeof(DispatcherQueueOptions), DQTYPE_THREAD_CURRENT, DQTAT_COM_STA };
winrt::Windows::System::DispatcherQueueController controller{ nullptr };
ABI::Windows::System::IDispatcherQueueController* rawController = nullptr;
HRESULT queueHr = CreateDispatcherQueueController(options, &rawController);
if (FAILED(queueHr) || !rawController) {
OutputDebugStringA("[ERROR] Failed to create DispatcherQueueController\n");
return;
}
controller = reinterpret_cast(rawController);
auto dispatcherQueue = controller.DispatcherQueue();
// Initialize Direct3D 11
ComPtr d3dDevice;
ComPtr d3dContext;
HRESULT hr = InitializeD3D11(d3dDevice, d3dContext);
if (FAILED(hr)) {
OutputDebugStringA("[ERROR] Failed to initialize D3D11 device.\n");
return;
}
// Create capture item
ComPtr captureInterop;
winrt::hstring className = L"Windows.Graphics.Capture.GraphicsCaptureItem";
hr = RoGetActivationFactory(
reinterpret_cast(winrt::get_abi(className)),
__uuidof(IGraphicsCaptureItemInterop),
reinterpret_cast(captureInterop.GetAddressOf())
);
if (FAILED(hr)) return;
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item{ nullptr };
hr = captureInterop->CreateForWindow(
hwnd,
winrt::guid_of(),
reinterpret_cast(winrt::put_abi(item))
);
if (FAILED(hr)) return;
ComPtr dxgiDevice;
hr = d3dDevice.As(&dxgiDevice);
if (FAILED(hr)) return;
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice winrtDevice = nullptr;
hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.Get(), reinterpret_cast(winrt::put_abi(winrtDevice)));
if (FAILED(hr)) return;
auto size = item.Size();
auto framePool = winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::Create(
winrtDevice,
winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, size
);
auto session = framePool.CreateCaptureSession(item);
session.IsCursorCaptureEnabled(false);
{
std::unique_lock lock(captureMutex);
captureSessions[sessionKey] = captureSession;
captureSession->d3dDevice = d3dDevice;
captureSession->d3dContext = d3dContext;
captureSession->framePool = framePool;
captureSession->session = session;
captureSession->item = item;
}
framePool.FrameArrived([sessionKey, captureSession](auto sender, auto args) {
//OutputDebugStringA("[INFO] FrameArrived event triggered.\n");
{
std::shared_lock lock(captureMutex);
if (captureSessions.find(sessionKey) == captureSessions.end()) {
OutputDebugStringA("[WARNING] Capture session missing in FrameArrived!\n");
return;
}
}
OnFrameArrived(sessionKey, sender, args);
});
session.StartCapture(); // Start after event setup
OutputDebugStringA("[INFO] Capture session started successfully.\n");
// Keep thread alive
MSG msg;
while (true) {
{
std::shared_lock lock(captureMutex);
if (captureSessions.find(sessionKey) == captureSessions.end()) {
OutputDebugStringA("[CRITICAL] Capture session unexpectedly removed from map!\n");
break;
}
}
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Log active session
static int frameCounter = 0;
frameCounter++;
if (frameCounter % 100 == 0) {
OutputDebugStringA("[INFO] Capture session is still active.\n");
}
std::this_thread::sleep_for(std::chrono::milliseconds(16)); // Allow thread to breathe
}
OutputDebugStringA("[ERROR] Capture session lost unexpectedly\n");
}).detach();
return true;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Подробнее здесь: https://stackoverflow.com/questions/794 ... cs-capture
Мобильная версия