mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
Use sdl2 to display capture screen
This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
#include "pch.h"
|
||||
#include "wgc_session_impl.h"
|
||||
|
||||
#include <Windows.Graphics.Capture.Interop.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#define CHECK_INIT \
|
||||
if (!is_initialized_) \
|
||||
return AM_ERROR::AE_NEED_INIT
|
||||
#define CHECK_INIT \
|
||||
if (!is_initialized_) { \
|
||||
std::cout << "AE_NEED_INIT" << std::endl; \
|
||||
return 4; \
|
||||
}
|
||||
|
||||
#define CHECK_CLOSED \
|
||||
if (cleaned_.load() == true) { \
|
||||
throw winrt::hresult_error(RO_E_CLOSED); \
|
||||
#define CHECK_CLOSED \
|
||||
if (cleaned_.load() == true) { \
|
||||
throw winrt::hresult_error(RO_E_CLOSED); \
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@@ -17,45 +23,42 @@ HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
|
||||
::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice);
|
||||
}
|
||||
|
||||
namespace am {
|
||||
WgcSessionImpl::WgcSessionImpl() {}
|
||||
|
||||
wgc_session_impl::wgc_session_impl() {}
|
||||
|
||||
wgc_session_impl::~wgc_session_impl() {
|
||||
stop();
|
||||
cleanup();
|
||||
WgcSessionImpl::~WgcSessionImpl() {
|
||||
Stop();
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
void wgc_session_impl::release() { delete this; }
|
||||
void WgcSessionImpl::Release() { delete this; }
|
||||
|
||||
int wgc_session_impl::initialize(HWND hwnd) {
|
||||
int WgcSessionImpl::Initialize(HWND hwnd) {
|
||||
std::lock_guard locker(lock_);
|
||||
|
||||
target_.hwnd = hwnd;
|
||||
target_.is_window = true;
|
||||
return initialize();
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
int wgc_session_impl::initialize(HMONITOR hmonitor) {
|
||||
int WgcSessionImpl::Initialize(HMONITOR hmonitor) {
|
||||
std::lock_guard locker(lock_);
|
||||
|
||||
target_.hmonitor = hmonitor;
|
||||
target_.is_window = false;
|
||||
return initialize();
|
||||
return Initialize();
|
||||
}
|
||||
|
||||
void wgc_session_impl::register_observer(wgc_session_observer *observer) {
|
||||
void WgcSessionImpl::RegisterObserver(wgc_session_observer *observer) {
|
||||
std::lock_guard locker(lock_);
|
||||
observer_ = observer;
|
||||
}
|
||||
|
||||
int wgc_session_impl::start() {
|
||||
int WgcSessionImpl::Start() {
|
||||
std::lock_guard locker(lock_);
|
||||
|
||||
if (is_running_)
|
||||
return AM_ERROR::AE_NO;
|
||||
if (is_running_) return 0;
|
||||
|
||||
int error = AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
||||
int error = 1;
|
||||
|
||||
CHECK_INIT;
|
||||
try {
|
||||
@@ -70,106 +73,95 @@ int wgc_session_impl::start() {
|
||||
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
|
||||
capture_frame_size_ = current_size;
|
||||
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
|
||||
winrt::auto_revoke, {this, &wgc_session_impl::on_frame});
|
||||
winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame});
|
||||
capture_close_trigger_ = capture_item_.Closed(
|
||||
winrt::auto_revoke, {this, &wgc_session_impl::on_closed});
|
||||
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
|
||||
}
|
||||
|
||||
if (!capture_framepool_)
|
||||
throw std::exception();
|
||||
if (!capture_framepool_) throw std::exception();
|
||||
|
||||
is_running_ = true;
|
||||
|
||||
// we do not need to crate a thread to enter a message loop coz we use
|
||||
// CreateFreeThreaded instead of Create to create a capture frame pool,
|
||||
// we need to test the performance later
|
||||
// loop_ = std::thread(std::bind(&wgc_session_impl::message_func, this));
|
||||
// loop_ = std::thread(std::bind(&WgcSessionImpl::message_func, this));
|
||||
|
||||
capture_session_.StartCapture();
|
||||
|
||||
error = AM_ERROR::AE_NO;
|
||||
error = 0;
|
||||
} catch (winrt::hresult_error) {
|
||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
||||
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
|
||||
return 86;
|
||||
} catch (...) {
|
||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
||||
return 86;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int wgc_session_impl::stop() {
|
||||
int WgcSessionImpl::Stop() {
|
||||
std::lock_guard locker(lock_);
|
||||
|
||||
CHECK_INIT;
|
||||
|
||||
is_running_ = false;
|
||||
|
||||
if (loop_.joinable())
|
||||
loop_.join();
|
||||
// if (loop_.joinable()) loop_.join();
|
||||
|
||||
if (capture_framepool_trigger_)
|
||||
capture_framepool_trigger_.revoke();
|
||||
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
|
||||
|
||||
if (capture_session_) {
|
||||
capture_session_.Close();
|
||||
capture_session_ = nullptr;
|
||||
}
|
||||
|
||||
return AM_ERROR::AE_NO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wgc_session_impl::pause() {
|
||||
int WgcSessionImpl::Pause() {
|
||||
std::lock_guard locker(lock_);
|
||||
|
||||
CHECK_INIT;
|
||||
return AM_ERROR::AE_NO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wgc_session_impl::resume() {
|
||||
int WgcSessionImpl::Resume() {
|
||||
std::lock_guard locker(lock_);
|
||||
|
||||
CHECK_INIT;
|
||||
return AM_ERROR::AE_NO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto wgc_session_impl::create_d3d11_device() {
|
||||
auto create_d3d_device = [](D3D_DRIVER_TYPE const type,
|
||||
winrt::com_ptr<ID3D11Device> &device) {
|
||||
WINRT_ASSERT(!device);
|
||||
auto WgcSessionImpl::CreateD3D11Device() {
|
||||
winrt::com_ptr<ID3D11Device> d3d_device;
|
||||
HRESULT hr;
|
||||
|
||||
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||
WINRT_ASSERT(!d3d_device);
|
||||
|
||||
//#ifdef _DEBUG
|
||||
// flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
//#endif
|
||||
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE;
|
||||
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
|
||||
D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr);
|
||||
|
||||
return ::D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
|
||||
D3D11_SDK_VERSION, device.put(), nullptr,
|
||||
nullptr);
|
||||
};
|
||||
auto create_d3d_device_wrapper = [&create_d3d_device]() {
|
||||
winrt::com_ptr<ID3D11Device> device;
|
||||
HRESULT hr = create_d3d_device(D3D_DRIVER_TYPE_HARDWARE, device);
|
||||
if (DXGI_ERROR_UNSUPPORTED == hr) {
|
||||
// change D3D_DRIVER_TYPE
|
||||
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_WARP;
|
||||
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
|
||||
D3D11_SDK_VERSION, d3d_device.put(), nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (DXGI_ERROR_UNSUPPORTED == hr) {
|
||||
hr = create_d3d_device(D3D_DRIVER_TYPE_WARP, device);
|
||||
}
|
||||
|
||||
winrt::check_hresult(hr);
|
||||
return device;
|
||||
};
|
||||
|
||||
auto d3d_device = create_d3d_device_wrapper();
|
||||
auto dxgi_device = d3d_device.as<IDXGIDevice>();
|
||||
winrt::check_hresult(hr);
|
||||
|
||||
winrt::com_ptr<::IInspectable> d3d11_device;
|
||||
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(
|
||||
dxgi_device.get(), d3d11_device.put()));
|
||||
d3d_device.as<IDXGIDevice>().get(), d3d11_device.put()));
|
||||
return d3d11_device
|
||||
.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
|
||||
}
|
||||
|
||||
auto wgc_session_impl::create_capture_item(HWND hwnd) {
|
||||
auto WgcSessionImpl::CreateCaptureItemForWindow(HWND hwnd) {
|
||||
auto activation_factory = winrt::get_activation_factory<
|
||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
||||
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
||||
@@ -181,7 +173,7 @@ auto wgc_session_impl::create_capture_item(HWND hwnd) {
|
||||
return item;
|
||||
}
|
||||
|
||||
auto wgc_session_impl::create_capture_item(HMONITOR hmonitor) {
|
||||
auto WgcSessionImpl::CreateCaptureItemForMonitor(HMONITOR hmonitor) {
|
||||
auto activation_factory = winrt::get_activation_factory<
|
||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
||||
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
||||
@@ -193,10 +185,9 @@ auto wgc_session_impl::create_capture_item(HMONITOR hmonitor) {
|
||||
return item;
|
||||
}
|
||||
|
||||
HRESULT wgc_session_impl::create_mapped_texture(
|
||||
HRESULT WgcSessionImpl::CreateMappedTexture(
|
||||
winrt::com_ptr<ID3D11Texture2D> src_texture, unsigned int width,
|
||||
unsigned int height) {
|
||||
|
||||
D3D11_TEXTURE2D_DESC src_desc;
|
||||
src_texture->GetDesc(&src_desc);
|
||||
D3D11_TEXTURE2D_DESC map_desc;
|
||||
@@ -211,13 +202,14 @@ HRESULT wgc_session_impl::create_mapped_texture(
|
||||
map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
map_desc.MiscFlags = 0;
|
||||
|
||||
auto d3dDevice = get_dxgi_interface<ID3D11Device>(d3d11_direct_device_);
|
||||
auto d3dDevice =
|
||||
GetDXGIInterfaceFromObject<ID3D11Device>(d3d11_direct_device_);
|
||||
|
||||
return d3dDevice->CreateTexture2D(&map_desc, nullptr,
|
||||
d3d11_texture_mapped_.put());
|
||||
}
|
||||
|
||||
void wgc_session_impl::on_frame(
|
||||
void WgcSessionImpl::OnFrame(
|
||||
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender,
|
||||
winrt::Windows::Foundation::IInspectable const &args) {
|
||||
std::lock_guard locker(lock_);
|
||||
@@ -240,10 +232,10 @@ void wgc_session_impl::on_frame(
|
||||
// copy to mapped texture
|
||||
{
|
||||
auto frame_captured =
|
||||
get_dxgi_interface<ID3D11Texture2D>(frame.Surface());
|
||||
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
||||
|
||||
if (!d3d11_texture_mapped_ || is_new_size)
|
||||
create_mapped_texture(frame_captured);
|
||||
CreateMappedTexture(frame_captured);
|
||||
|
||||
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
|
||||
frame_captured.get());
|
||||
@@ -262,61 +254,12 @@ void wgc_session_impl::on_frame(
|
||||
|
||||
// copy data from map_result.pData
|
||||
if (map_result.pData && observer_) {
|
||||
observer_->on_frame(wgc_session_frame{
|
||||
observer_->OnFrame(wgc_session_frame{
|
||||
static_cast<unsigned int>(frame_size.Width),
|
||||
static_cast<unsigned int>(frame_size.Height), map_result.RowPitch,
|
||||
const_cast<const unsigned char *>(
|
||||
(unsigned char *)map_result.pData)});
|
||||
}
|
||||
#if 0
|
||||
if (map_result.pData) {
|
||||
static unsigned char *buffer = nullptr;
|
||||
if (buffer && is_new_size)
|
||||
delete[] buffer;
|
||||
|
||||
if (!buffer)
|
||||
buffer = new unsigned char[frame_size.Width * frame_size.Height * 4];
|
||||
|
||||
int dstRowPitch = frame_size.Width * 4;
|
||||
for (int h = 0; h < frame_size.Height; h++) {
|
||||
memcpy_s(buffer + h * dstRowPitch, dstRowPitch,
|
||||
(BYTE *)map_result.pData + h * map_result.RowPitch,
|
||||
min(map_result.RowPitch, dstRowPitch));
|
||||
}
|
||||
|
||||
BITMAPINFOHEADER bi;
|
||||
|
||||
bi.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bi.biWidth = frame_size.Width;
|
||||
bi.biHeight = frame_size.Height * (-1);
|
||||
bi.biPlanes = 1;
|
||||
bi.biBitCount = 32; // should get from system color bits
|
||||
bi.biCompression = BI_RGB;
|
||||
bi.biSizeImage = 0;
|
||||
bi.biXPelsPerMeter = 0;
|
||||
bi.biYPelsPerMeter = 0;
|
||||
bi.biClrUsed = 0;
|
||||
bi.biClrImportant = 0;
|
||||
|
||||
BITMAPFILEHEADER bf;
|
||||
bf.bfType = 0x4d42;
|
||||
bf.bfReserved1 = 0;
|
||||
bf.bfReserved2 = 0;
|
||||
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||||
bf.bfSize = bf.bfOffBits + frame_size.Width * frame_size.Height * 4;
|
||||
|
||||
FILE *fp = nullptr;
|
||||
|
||||
fopen_s(&fp, ".\\save.bmp", "wb+");
|
||||
|
||||
fwrite(&bf, 1, sizeof(bf), fp);
|
||||
fwrite(&bi, 1, sizeof(bi), fp);
|
||||
fwrite(buffer, 1, frame_size.Width * frame_size.Height * 4, fp);
|
||||
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
#endif
|
||||
|
||||
d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
|
||||
}
|
||||
@@ -330,41 +273,44 @@ void wgc_session_impl::on_frame(
|
||||
}
|
||||
}
|
||||
|
||||
void wgc_session_impl::on_closed(
|
||||
void WgcSessionImpl::OnClosed(
|
||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
|
||||
winrt::Windows::Foundation::IInspectable const &) {
|
||||
OutputDebugStringW(L"wgc_session_impl::on_closed");
|
||||
OutputDebugStringW(L"WgcSessionImpl::OnClosed");
|
||||
}
|
||||
|
||||
int wgc_session_impl::initialize() {
|
||||
if (is_initialized_)
|
||||
return AM_ERROR::AE_NO;
|
||||
int WgcSessionImpl::Initialize() {
|
||||
if (is_initialized_) return 0;
|
||||
|
||||
if (!(d3d11_direct_device_ = create_d3d11_device()))
|
||||
return AM_ERROR::AE_D3D_CREATE_DEVICE_FAILED;
|
||||
if (!(d3d11_direct_device_ = CreateD3D11Device())) {
|
||||
std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
if (target_.is_window)
|
||||
capture_item_ = create_capture_item(target_.hwnd);
|
||||
capture_item_ = CreateCaptureItemForWindow(target_.hwnd);
|
||||
else
|
||||
capture_item_ = create_capture_item(target_.hmonitor);
|
||||
capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor);
|
||||
|
||||
// Set up
|
||||
auto d3d11_device = get_dxgi_interface<ID3D11Device>(d3d11_direct_device_);
|
||||
auto d3d11_device =
|
||||
GetDXGIInterfaceFromObject<ID3D11Device>(d3d11_direct_device_);
|
||||
d3d11_device->GetImmediateContext(d3d11_device_context_.put());
|
||||
|
||||
} catch (winrt::hresult_error) {
|
||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
||||
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
|
||||
return 86;
|
||||
} catch (...) {
|
||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
||||
return 86;
|
||||
}
|
||||
|
||||
is_initialized_ = true;
|
||||
|
||||
return AM_ERROR::AE_NO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wgc_session_impl::cleanup() {
|
||||
void WgcSessionImpl::CleanUp() {
|
||||
std::lock_guard locker(lock_);
|
||||
|
||||
auto expected = false;
|
||||
@@ -372,11 +318,9 @@ void wgc_session_impl::cleanup() {
|
||||
capture_close_trigger_.revoke();
|
||||
capture_framepool_trigger_.revoke();
|
||||
|
||||
if (capture_framepool_)
|
||||
capture_framepool_.Close();
|
||||
if (capture_framepool_) capture_framepool_.Close();
|
||||
|
||||
if (capture_session_)
|
||||
capture_session_.Close();
|
||||
if (capture_session_) capture_session_.Close();
|
||||
|
||||
capture_framepool_ = nullptr;
|
||||
capture_session_ = nullptr;
|
||||
@@ -391,35 +335,32 @@ LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param,
|
||||
return DefWindowProc(window, message, w_param, l_param);
|
||||
}
|
||||
|
||||
void wgc_session_impl::message_func() {
|
||||
const std::wstring kClassName = L"am_fake_window";
|
||||
// void WgcSessionImpl::message_func() {
|
||||
// const std::wstring kClassName = L"am_fake_window";
|
||||
|
||||
WNDCLASS wc = {};
|
||||
// WNDCLASS wc = {};
|
||||
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
|
||||
wc.lpszClassName = kClassName.c_str();
|
||||
// wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
// wc.lpfnWndProc = DefWindowProc;
|
||||
// wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
// wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
|
||||
// wc.lpszClassName = kClassName.c_str();
|
||||
|
||||
if (!::RegisterClassW(&wc))
|
||||
return;
|
||||
// if (!::RegisterClassW(&wc)) return;
|
||||
|
||||
hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW, 0,
|
||||
0, 0, 0, nullptr, nullptr, nullptr, nullptr);
|
||||
MSG msg;
|
||||
while (is_running_) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
if (!is_running_)
|
||||
break;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
Sleep(10);
|
||||
}
|
||||
// hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW,
|
||||
// 0,
|
||||
// 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
|
||||
// MSG msg;
|
||||
// while (is_running_) {
|
||||
// while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
// if (!is_running_) break;
|
||||
// TranslateMessage(&msg);
|
||||
// DispatchMessage(&msg);
|
||||
// }
|
||||
// Sleep(10);
|
||||
// }
|
||||
|
||||
::CloseWindow(hwnd_);
|
||||
::DestroyWindow(hwnd_);
|
||||
}
|
||||
|
||||
} // namespace am
|
||||
// ::CloseWindow(hwnd_);
|
||||
// ::DestroyWindow(hwnd_);
|
||||
// }
|
||||
Reference in New Issue
Block a user