| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 | 
							- #include "winrt-capture.h"
 
- extern "C" {
 
- HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
 
- 	::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice);
 
- HRESULT __stdcall CreateDirect3D11SurfaceFromDXGISurface(
 
- 	::IDXGISurface *dgxiSurface, ::IInspectable **graphicsSurface);
 
- }
 
- struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
 
- 	IDirect3DDxgiInterfaceAccess : ::IUnknown {
 
- 	virtual HRESULT __stdcall GetInterface(GUID const &id,
 
- 					       void **object) = 0;
 
- };
 
- extern "C" EXPORT BOOL winrt_capture_supported()
 
- try {
 
- 	/* no contract for IGraphicsCaptureItemInterop, verify 10.0.18362.0 */
 
- 	return winrt::Windows::Foundation::Metadata::ApiInformation::
 
- 		IsApiContractPresent(L"Windows.Foundation.UniversalApiContract",
 
- 				     8);
 
- } catch (const winrt::hresult_error &err) {
 
- 	blog(LOG_ERROR, "winrt_capture_supported (0x%08X): %ls",
 
- 	     err.code().value, err.message().c_str());
 
- 	return false;
 
- } catch (...) {
 
- 	blog(LOG_ERROR, "winrt_capture_supported (0x%08X)",
 
- 	     winrt::to_hresult().value);
 
- 	return false;
 
- }
 
- extern "C" EXPORT BOOL winrt_capture_cursor_toggle_supported()
 
- try {
 
- 	return winrt::Windows::Foundation::Metadata::ApiInformation::
 
- 		IsPropertyPresent(
 
- 			L"Windows.Graphics.Capture.GraphicsCaptureSession",
 
- 			L"IsCursorCaptureEnabled");
 
- } catch (const winrt::hresult_error &err) {
 
- 	blog(LOG_ERROR, "winrt_capture_cursor_toggle_supported (0x%08X): %ls",
 
- 	     err.code().value, err.message().c_str());
 
- 	return false;
 
- } catch (...) {
 
- 	blog(LOG_ERROR, "winrt_capture_cursor_toggle_supported (0x%08X)",
 
- 	     winrt::to_hresult().value);
 
- 	return false;
 
- }
 
- template<typename T>
 
- static winrt::com_ptr<T> GetDXGIInterfaceFromObject(
 
- 	winrt::Windows::Foundation::IInspectable const &object)
 
- {
 
- 	auto access = object.as<IDirect3DDxgiInterfaceAccess>();
 
- 	winrt::com_ptr<T> result;
 
- 	winrt::check_hresult(
 
- 		access->GetInterface(winrt::guid_of<T>(), result.put_void()));
 
- 	return result;
 
- }
 
- static bool get_client_box(HWND window, uint32_t width, uint32_t height,
 
- 			   D3D11_BOX *client_box)
 
- {
 
- 	RECT client_rect{}, window_rect{};
 
- 	POINT upper_left{};
 
- 	/* check iconic (minimized) twice, ABA is very unlikely */
 
- 	bool client_box_available =
 
- 		!IsIconic(window) && GetClientRect(window, &client_rect) &&
 
- 		!IsIconic(window) && (client_rect.right > 0) &&
 
- 		(client_rect.bottom > 0) &&
 
- 		(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS,
 
- 				       &window_rect,
 
- 				       sizeof(window_rect)) == S_OK) &&
 
- 		ClientToScreen(window, &upper_left);
 
- 	if (client_box_available) {
 
- 		const uint32_t left =
 
- 			(upper_left.x > window_rect.left)
 
- 				? (upper_left.x - window_rect.left)
 
- 				: 0;
 
- 		client_box->left = left;
 
- 		const uint32_t top = (upper_left.y > window_rect.top)
 
- 					     ? (upper_left.y - window_rect.top)
 
- 					     : 0;
 
- 		client_box->top = top;
 
- 		uint32_t texture_width = 1;
 
- 		if (width > left) {
 
- 			texture_width =
 
- 				min(width - left, (uint32_t)client_rect.right);
 
- 		}
 
- 		uint32_t texture_height = 1;
 
- 		if (height > top) {
 
- 			texture_height =
 
- 				min(height - top, (uint32_t)client_rect.bottom);
 
- 		}
 
- 		client_box->right = left + texture_width;
 
- 		client_box->bottom = top + texture_height;
 
- 		client_box->front = 0;
 
- 		client_box->back = 1;
 
- 		client_box_available = (client_box->right <= width) &&
 
- 				       (client_box->bottom <= height);
 
- 	}
 
- 	return client_box_available;
 
- }
 
- static DXGI_FORMAT get_pixel_format(HWND window, HMONITOR monitor,
 
- 				    BOOL force_sdr)
 
- {
 
- 	static constexpr DXGI_FORMAT sdr_format = DXGI_FORMAT_B8G8R8A8_UNORM;
 
- 	if (force_sdr)
 
- 		return sdr_format;
 
- 	if (window)
 
- 		monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
 
- 	return (monitor && gs_is_monitor_hdr(monitor))
 
- 		       ? DXGI_FORMAT_R16G16B16A16_FLOAT
 
- 		       : sdr_format;
 
- }
 
- struct winrt_capture {
 
- 	HWND window;
 
- 	BOOL client_area;
 
- 	BOOL force_sdr;
 
- 	HMONITOR monitor;
 
- 	DXGI_FORMAT format;
 
- 	bool capture_cursor;
 
- 	BOOL cursor_visible;
 
- 	gs_texture_t *texture;
 
- 	bool texture_written;
 
- 	winrt::Windows::Graphics::Capture::GraphicsCaptureItem item{nullptr};
 
- 	winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice device{
 
- 		nullptr};
 
- 	ComPtr<ID3D11DeviceContext> context;
 
- 	winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool frame_pool{
 
- 		nullptr};
 
- 	winrt::Windows::Graphics::Capture::GraphicsCaptureSession session{
 
- 		nullptr};
 
- 	winrt::Windows::Graphics::SizeInt32 last_size;
 
- 	winrt::Windows::Graphics::Capture::GraphicsCaptureItem::Closed_revoker
 
- 		closed;
 
- 	winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
 
- 		FrameArrived_revoker frame_arrived;
 
- 	uint32_t texture_width;
 
- 	uint32_t texture_height;
 
- 	D3D11_BOX client_box;
 
- 	BOOL active;
 
- 	struct winrt_capture *next;
 
- 	void on_closed(
 
- 		winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
 
- 		winrt::Windows::Foundation::IInspectable const &)
 
- 	{
 
- 		active = FALSE;
 
- 	}
 
- 	void on_frame_arrived(winrt::Windows::Graphics::Capture::
 
- 				      Direct3D11CaptureFramePool const &sender,
 
- 			      winrt::Windows::Foundation::IInspectable const &)
 
- 	{
 
- 		const winrt::Windows::Graphics::Capture::Direct3D11CaptureFrame
 
- 			frame = sender.TryGetNextFrame();
 
- 		const winrt::Windows::Graphics::SizeInt32 frame_content_size =
 
- 			frame.ContentSize();
 
- 		winrt::com_ptr<ID3D11Texture2D> frame_surface =
 
- 			GetDXGIInterfaceFromObject<ID3D11Texture2D>(
 
- 				frame.Surface());
 
- 		/* need GetDesc because ContentSize is not reliable */
 
- 		D3D11_TEXTURE2D_DESC desc;
 
- 		frame_surface->GetDesc(&desc);
 
- 		obs_enter_graphics();
 
- 		if (desc.Format ==
 
- 		    get_pixel_format(window, monitor, force_sdr)) {
 
- 			if (!client_area ||
 
- 			    get_client_box(window, desc.Width, desc.Height,
 
- 					   &client_box)) {
 
- 				if (client_area) {
 
- 					texture_width = client_box.right -
 
- 							client_box.left;
 
- 					texture_height = client_box.bottom -
 
- 							 client_box.top;
 
- 				} else {
 
- 					texture_width = desc.Width;
 
- 					texture_height = desc.Height;
 
- 				}
 
- 				if (texture) {
 
- 					if (texture_width !=
 
- 						    gs_texture_get_width(
 
- 							    texture) ||
 
- 					    texture_height !=
 
- 						    gs_texture_get_height(
 
- 							    texture)) {
 
- 						gs_texture_destroy(texture);
 
- 						texture = nullptr;
 
- 					}
 
- 				}
 
- 				if (!texture) {
 
- 					const gs_color_format color_format =
 
- 						desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT
 
- 							? GS_RGBA16F
 
- 							: GS_BGRA;
 
- 					texture = gs_texture_create(
 
- 						texture_width, texture_height,
 
- 						color_format, 1, NULL, 0);
 
- 				}
 
- 				if (client_area) {
 
- 					context->CopySubresourceRegion(
 
- 						(ID3D11Texture2D *)
 
- 							gs_texture_get_obj(
 
- 								texture),
 
- 						0, 0, 0, 0, frame_surface.get(),
 
- 						0, &client_box);
 
- 				} else {
 
- 					/* if they gave an SRV, we could avoid this copy */
 
- 					context->CopyResource(
 
- 						(ID3D11Texture2D *)
 
- 							gs_texture_get_obj(
 
- 								texture),
 
- 						frame_surface.get());
 
- 				}
 
- 				texture_written = true;
 
- 			}
 
- 			if (frame_content_size.Width != last_size.Width ||
 
- 			    frame_content_size.Height != last_size.Height) {
 
- 				format = desc.Format;
 
- 				frame_pool.Recreate(
 
- 					device,
 
- 					static_cast<
 
- 						winrt::Windows::Graphics::DirectX::
 
- 							DirectXPixelFormat>(
 
- 						format),
 
- 					2, frame_content_size);
 
- 				last_size = frame_content_size;
 
- 			}
 
- 		} else {
 
- 			active = FALSE;
 
- 		}
 
- 		obs_leave_graphics();
 
- 	}
 
- };
 
- static struct winrt_capture *capture_list;
 
- static void winrt_capture_device_loss_release(void *data)
 
- {
 
- 	winrt_capture *capture = static_cast<winrt_capture *>(data);
 
- 	capture->active = FALSE;
 
- 	capture->frame_arrived.revoke();
 
- 	try {
 
- 		capture->frame_pool.Close();
 
- 	} catch (winrt::hresult_error &err) {
 
- 		blog(LOG_ERROR,
 
- 		     "Direct3D11CaptureFramePool::Close (0x%08X): %ls",
 
- 		     err.code().value, err.message().c_str());
 
- 	} catch (...) {
 
- 		blog(LOG_ERROR, "Direct3D11CaptureFramePool::Close (0x%08X)",
 
- 		     winrt::to_hresult().value);
 
- 	}
 
- 	try {
 
- 		capture->session.Close();
 
- 	} catch (winrt::hresult_error &err) {
 
- 		blog(LOG_ERROR, "GraphicsCaptureSession::Close (0x%08X): %ls",
 
- 		     err.code().value, err.message().c_str());
 
- 	} catch (...) {
 
- 		blog(LOG_ERROR, "GraphicsCaptureSession::Close (0x%08X)",
 
- 		     winrt::to_hresult().value);
 
- 	}
 
- 	capture->session = nullptr;
 
- 	capture->frame_pool = nullptr;
 
- 	capture->context = nullptr;
 
- 	capture->device = nullptr;
 
- 	capture->item = nullptr;
 
- }
 
- static bool winrt_capture_border_toggle_supported()
 
- try {
 
- 	return winrt::Windows::Foundation::Metadata::ApiInformation::
 
- 		IsPropertyPresent(
 
- 			L"Windows.Graphics.Capture.GraphicsCaptureSession",
 
- 			L"IsBorderRequired");
 
- } catch (const winrt::hresult_error &err) {
 
- 	blog(LOG_ERROR, "winrt_capture_border_toggle_supported (0x%08X): %ls",
 
- 	     err.code().value, err.message().c_str());
 
- 	return false;
 
- } catch (...) {
 
- 	blog(LOG_ERROR, "winrt_capture_border_toggle_supported (0x%08X)",
 
- 	     winrt::to_hresult().value);
 
- 	return false;
 
- }
 
- static winrt::Windows::Graphics::Capture::GraphicsCaptureItem
 
- winrt_capture_create_item(IGraphicsCaptureItemInterop *const interop_factory,
 
- 			  HWND window, HMONITOR monitor)
 
- {
 
- 	winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
 
- 	if (window) {
 
- 		try {
 
- 			const HRESULT hr = interop_factory->CreateForWindow(
 
- 				window,
 
- 				winrt::guid_of<ABI::Windows::Graphics::Capture::
 
- 						       IGraphicsCaptureItem>(),
 
- 				reinterpret_cast<void **>(
 
- 					winrt::put_abi(item)));
 
- 			if (FAILED(hr))
 
- 				blog(LOG_ERROR, "CreateForWindow (0x%08X)", hr);
 
- 		} catch (winrt::hresult_error &err) {
 
- 			blog(LOG_ERROR, "CreateForWindow (0x%08X): %ls",
 
- 			     err.code().value, err.message().c_str());
 
- 		} catch (...) {
 
- 			blog(LOG_ERROR, "CreateForWindow (0x%08X)",
 
- 			     winrt::to_hresult().value);
 
- 		}
 
- 	} else {
 
- 		assert(monitor);
 
- 		try {
 
- 			const HRESULT hr = interop_factory->CreateForMonitor(
 
- 				monitor,
 
- 				winrt::guid_of<ABI::Windows::Graphics::Capture::
 
- 						       IGraphicsCaptureItem>(),
 
- 				reinterpret_cast<void **>(
 
- 					winrt::put_abi(item)));
 
- 			if (FAILED(hr))
 
- 				blog(LOG_ERROR, "CreateForMonitor (0x%08X)",
 
- 				     hr);
 
- 		} catch (winrt::hresult_error &err) {
 
- 			blog(LOG_ERROR, "CreateForMonitor (0x%08X): %ls",
 
- 			     err.code().value, err.message().c_str());
 
- 		} catch (...) {
 
- 			blog(LOG_ERROR, "CreateForMonitor (0x%08X)",
 
- 			     winrt::to_hresult().value);
 
- 		}
 
- 	}
 
- 	return item;
 
- }
 
- static void winrt_capture_device_loss_rebuild(void *device_void, void *data)
 
- {
 
- 	winrt_capture *capture = static_cast<winrt_capture *>(data);
 
- 	auto activation_factory = winrt::get_activation_factory<
 
- 		winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
 
- 	auto interop_factory =
 
- 		activation_factory.as<IGraphicsCaptureItemInterop>();
 
- 	winrt::Windows::Graphics::Capture::GraphicsCaptureItem item =
 
- 		winrt_capture_create_item(interop_factory.get(),
 
- 					  capture->window, capture->monitor);
 
- 	if (!item)
 
- 		return;
 
- 	ID3D11Device *const d3d_device = (ID3D11Device *)device_void;
 
- 	ComPtr<IDXGIDevice> dxgi_device;
 
- 	if (FAILED(d3d_device->QueryInterface(&dxgi_device)))
 
- 		blog(LOG_ERROR, "Failed to get DXGI device");
 
- 	winrt::com_ptr<IInspectable> inspectable;
 
- 	if (FAILED(CreateDirect3D11DeviceFromDXGIDevice(dxgi_device.Get(),
 
- 							inspectable.put())))
 
- 		blog(LOG_ERROR, "Failed to get WinRT device");
 
- 	const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice
 
- 		device = inspectable.as<winrt::Windows::Graphics::DirectX::
 
- 						Direct3D11::IDirect3DDevice>();
 
- 	const winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool
 
- 		frame_pool = winrt::Windows::Graphics::Capture::
 
- 			Direct3D11CaptureFramePool::Create(
 
- 				device,
 
- 				static_cast<winrt::Windows::Graphics::DirectX::
 
- 						    DirectXPixelFormat>(
 
- 					capture->format),
 
- 				2, capture->last_size);
 
- 	const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session =
 
- 		frame_pool.CreateCaptureSession(item);
 
- 	if (winrt_capture_border_toggle_supported()) {
 
- 		winrt::Windows::Graphics::Capture::GraphicsCaptureAccess::
 
- 			RequestAccessAsync(
 
- 				winrt::Windows::Graphics::Capture::
 
- 					GraphicsCaptureAccessKind::Borderless)
 
- 				.get();
 
- 		session.IsBorderRequired(false);
 
- 	}
 
- 	if (winrt_capture_cursor_toggle_supported())
 
- 		session.IsCursorCaptureEnabled(capture->capture_cursor &&
 
- 					       capture->cursor_visible);
 
- 	capture->item = item;
 
- 	capture->device = device;
 
- 	d3d_device->GetImmediateContext(&capture->context);
 
- 	capture->frame_pool = frame_pool;
 
- 	capture->session = session;
 
- 	capture->frame_arrived = frame_pool.FrameArrived(
 
- 		winrt::auto_revoke,
 
- 		{capture, &winrt_capture::on_frame_arrived});
 
- 	try {
 
- 		session.StartCapture();
 
- 		capture->active = TRUE;
 
- 	} catch (winrt::hresult_error &err) {
 
- 		blog(LOG_ERROR, "StartCapture (0x%08X): %ls", err.code().value,
 
- 		     err.message().c_str());
 
- 	} catch (...) {
 
- 		blog(LOG_ERROR, "StartCapture (0x%08X)",
 
- 		     winrt::to_hresult().value);
 
- 	}
 
- }
 
- static struct winrt_capture *
 
- winrt_capture_init_internal(BOOL cursor, HWND window, BOOL client_area,
 
- 			    BOOL force_sdr, HMONITOR monitor)
 
- try {
 
- 	ID3D11Device *const d3d_device = (ID3D11Device *)gs_get_device_obj();
 
- 	ComPtr<IDXGIDevice> dxgi_device;
 
- 	HRESULT hr = d3d_device->QueryInterface(&dxgi_device);
 
- 	if (FAILED(hr)) {
 
- 		blog(LOG_ERROR, "Failed to get DXGI device");
 
- 		return nullptr;
 
- 	}
 
- 	winrt::com_ptr<IInspectable> inspectable;
 
- 	hr = CreateDirect3D11DeviceFromDXGIDevice(dxgi_device.Get(),
 
- 						  inspectable.put());
 
- 	if (FAILED(hr)) {
 
- 		blog(LOG_ERROR, "Failed to get WinRT device");
 
- 		return nullptr;
 
- 	}
 
- 	auto activation_factory = winrt::get_activation_factory<
 
- 		winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
 
- 	auto interop_factory =
 
- 		activation_factory.as<IGraphicsCaptureItemInterop>();
 
- 	winrt::Windows::Graphics::Capture::GraphicsCaptureItem item =
 
- 		winrt_capture_create_item(interop_factory.get(), window,
 
- 					  monitor);
 
- 	if (!item)
 
- 		return nullptr;
 
- 	const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice
 
- 		device = inspectable.as<winrt::Windows::Graphics::DirectX::
 
- 						Direct3D11::IDirect3DDevice>();
 
- 	const winrt::Windows::Graphics::SizeInt32 size = item.Size();
 
- 	const DXGI_FORMAT format = get_pixel_format(window, monitor, force_sdr);
 
- 	const winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool
 
- 		frame_pool = winrt::Windows::Graphics::Capture::
 
- 			Direct3D11CaptureFramePool::Create(
 
- 				device,
 
- 				static_cast<winrt::Windows::Graphics::DirectX::
 
- 						    DirectXPixelFormat>(format),
 
- 				2, size);
 
- 	const winrt::Windows::Graphics::Capture::GraphicsCaptureSession session =
 
- 		frame_pool.CreateCaptureSession(item);
 
- 	if (winrt_capture_border_toggle_supported()) {
 
- 		winrt::Windows::Graphics::Capture::GraphicsCaptureAccess::
 
- 			RequestAccessAsync(
 
- 				winrt::Windows::Graphics::Capture::
 
- 					GraphicsCaptureAccessKind::Borderless)
 
- 				.get();
 
- 		session.IsBorderRequired(false);
 
- 	}
 
- 	/* disable cursor capture if possible since ours performs better */
 
- 	const BOOL cursor_toggle_supported =
 
- 		winrt_capture_cursor_toggle_supported();
 
- 	if (cursor_toggle_supported)
 
- 		session.IsCursorCaptureEnabled(cursor);
 
- 	struct winrt_capture *capture = new winrt_capture{};
 
- 	capture->window = window;
 
- 	capture->client_area = client_area;
 
- 	capture->force_sdr = force_sdr;
 
- 	capture->monitor = monitor;
 
- 	capture->format = format;
 
- 	capture->capture_cursor = cursor && cursor_toggle_supported;
 
- 	capture->cursor_visible = cursor;
 
- 	capture->item = item;
 
- 	capture->device = device;
 
- 	d3d_device->GetImmediateContext(&capture->context);
 
- 	capture->frame_pool = frame_pool;
 
- 	capture->session = session;
 
- 	capture->last_size = size;
 
- 	capture->closed = item.Closed(winrt::auto_revoke,
 
- 				      {capture, &winrt_capture::on_closed});
 
- 	capture->frame_arrived = frame_pool.FrameArrived(
 
- 		winrt::auto_revoke,
 
- 		{capture, &winrt_capture::on_frame_arrived});
 
- 	capture->next = capture_list;
 
- 	capture_list = capture;
 
- 	session.StartCapture();
 
- 	capture->active = TRUE;
 
- 	gs_device_loss callbacks;
 
- 	callbacks.device_loss_release = winrt_capture_device_loss_release;
 
- 	callbacks.device_loss_rebuild = winrt_capture_device_loss_rebuild;
 
- 	callbacks.data = capture;
 
- 	gs_register_loss_callbacks(&callbacks);
 
- 	return capture;
 
- } catch (const winrt::hresult_error &err) {
 
- 	blog(LOG_ERROR, "winrt_capture_init (0x%08X): %ls", err.code().value,
 
- 	     err.message().c_str());
 
- 	return nullptr;
 
- } catch (...) {
 
- 	blog(LOG_ERROR, "winrt_capture_init (0x%08X)",
 
- 	     winrt::to_hresult().value);
 
- 	return nullptr;
 
- }
 
- extern "C" EXPORT struct winrt_capture *
 
- winrt_capture_init_window(BOOL cursor, HWND window, BOOL client_area,
 
- 			  BOOL force_sdr)
 
- {
 
- 	return winrt_capture_init_internal(cursor, window, client_area,
 
- 					   force_sdr, NULL);
 
- }
 
- extern "C" EXPORT struct winrt_capture *
 
- winrt_capture_init_monitor(BOOL cursor, HMONITOR monitor)
 
- {
 
- 	return winrt_capture_init_internal(cursor, NULL, false, false, monitor);
 
- }
 
- extern "C" EXPORT void winrt_capture_free(struct winrt_capture *capture)
 
- {
 
- 	if (capture) {
 
- 		struct winrt_capture *current = capture_list;
 
- 		if (current == capture) {
 
- 			capture_list = capture->next;
 
- 		} else {
 
- 			struct winrt_capture *previous;
 
- 			do {
 
- 				previous = current;
 
- 				current = current->next;
 
- 			} while (current != capture);
 
- 			previous->next = current->next;
 
- 		}
 
- 		obs_enter_graphics();
 
- 		gs_unregister_loss_callbacks(capture);
 
- 		gs_texture_destroy(capture->texture);
 
- 		obs_leave_graphics();
 
- 		capture->frame_arrived.revoke();
 
- 		capture->closed.revoke();
 
- 		try {
 
- 			if (capture->frame_pool)
 
- 				capture->frame_pool.Close();
 
- 		} catch (winrt::hresult_error &err) {
 
- 			blog(LOG_ERROR,
 
- 			     "Direct3D11CaptureFramePool::Close (0x%08X): %ls",
 
- 			     err.code().value, err.message().c_str());
 
- 		} catch (...) {
 
- 			blog(LOG_ERROR,
 
- 			     "Direct3D11CaptureFramePool::Close (0x%08X)",
 
- 			     winrt::to_hresult().value);
 
- 		}
 
- 		try {
 
- 			if (capture->session)
 
- 				capture->session.Close();
 
- 		} catch (winrt::hresult_error &err) {
 
- 			blog(LOG_ERROR,
 
- 			     "GraphicsCaptureSession::Close (0x%08X): %ls",
 
- 			     err.code().value, err.message().c_str());
 
- 		} catch (...) {
 
- 			blog(LOG_ERROR,
 
- 			     "GraphicsCaptureSession::Close (0x%08X)",
 
- 			     winrt::to_hresult().value);
 
- 		}
 
- 		delete capture;
 
- 	}
 
- }
 
- extern "C" EXPORT BOOL winrt_capture_active(const struct winrt_capture *capture)
 
- {
 
- 	return capture->active;
 
- }
 
- extern "C" EXPORT BOOL winrt_capture_show_cursor(struct winrt_capture *capture,
 
- 						 BOOL visible)
 
- {
 
- 	BOOL success = FALSE;
 
- 	try {
 
- 		if (capture->capture_cursor) {
 
- 			if (capture->cursor_visible != visible) {
 
- 				capture->session.IsCursorCaptureEnabled(
 
- 					visible);
 
- 				capture->cursor_visible = visible;
 
- 			}
 
- 		}
 
- 		success = TRUE;
 
- 	} catch (winrt::hresult_error &err) {
 
- 		blog(LOG_ERROR,
 
- 		     "GraphicsCaptureSession::IsCursorCaptureEnabled (0x%08X): %ls",
 
- 		     err.code().value, err.message().c_str());
 
- 	} catch (...) {
 
- 		blog(LOG_ERROR,
 
- 		     "GraphicsCaptureSession::IsCursorCaptureEnabled (0x%08X)",
 
- 		     winrt::to_hresult().value);
 
- 	}
 
- 	return success;
 
- }
 
- extern "C" EXPORT enum gs_color_space
 
- winrt_capture_get_color_space(const struct winrt_capture *capture)
 
- {
 
- 	return (capture->format == DXGI_FORMAT_R16G16B16A16_FLOAT)
 
- 		       ? GS_CS_709_EXTENDED
 
- 		       : GS_CS_SRGB;
 
- }
 
- extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture)
 
- {
 
- 	if (capture->texture_written) {
 
- 		const char *tech_name = "Draw";
 
- 		float multiplier = 1.f;
 
- 		const gs_color_space current_space = gs_get_color_space();
 
- 		if (capture->format == DXGI_FORMAT_R16G16B16A16_FLOAT) {
 
- 			switch (current_space) {
 
- 			case GS_CS_SRGB:
 
- 			case GS_CS_SRGB_16F:
 
- 				tech_name = "DrawMultiplyTonemap";
 
- 				multiplier =
 
- 					80.f / obs_get_video_sdr_white_level();
 
- 				break;
 
- 			case GS_CS_709_EXTENDED:
 
- 				tech_name = "DrawMultiply";
 
- 				multiplier =
 
- 					80.f / obs_get_video_sdr_white_level();
 
- 			}
 
- 		} else if (current_space == GS_CS_709_SCRGB) {
 
- 			tech_name = "DrawMultiply";
 
- 			multiplier = obs_get_video_sdr_white_level() / 80.f;
 
- 		}
 
- 		gs_effect_t *const effect =
 
- 			obs_get_base_effect(OBS_EFFECT_DEFAULT);
 
- 		gs_technique_t *tech =
 
- 			gs_effect_get_technique(effect, tech_name);
 
- 		const bool previous = gs_framebuffer_srgb_enabled();
 
- 		gs_enable_framebuffer_srgb(true);
 
- 		gs_blend_state_push();
 
- 		gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
 
- 		gs_texture_t *const texture = capture->texture;
 
- 		gs_effect_set_texture_srgb(
 
- 			gs_effect_get_param_by_name(effect, "image"), texture);
 
- 		gs_effect_set_float(gs_effect_get_param_by_name(effect,
 
- 								"multiplier"),
 
- 				    multiplier);
 
- 		const size_t passes = gs_technique_begin(tech);
 
- 		for (size_t i = 0; i < passes; i++) {
 
- 			if (gs_technique_begin_pass(tech, i)) {
 
- 				gs_draw_sprite(texture, 0, 0, 0);
 
- 				gs_technique_end_pass(tech);
 
- 			}
 
- 		}
 
- 		gs_technique_end(tech);
 
- 		gs_blend_state_pop();
 
- 		gs_enable_framebuffer_srgb(previous);
 
- 	}
 
- }
 
- extern "C" EXPORT uint32_t
 
- winrt_capture_width(const struct winrt_capture *capture)
 
- {
 
- 	return capture ? capture->texture_width : 0;
 
- }
 
- extern "C" EXPORT uint32_t
 
- winrt_capture_height(const struct winrt_capture *capture)
 
- {
 
- 	return capture ? capture->texture_height : 0;
 
- }
 
- extern "C" EXPORT void winrt_capture_thread_start()
 
- {
 
- 	struct winrt_capture *capture = capture_list;
 
- 	void *const device = gs_get_device_obj();
 
- 	while (capture) {
 
- 		winrt_capture_device_loss_rebuild(device, capture);
 
- 		capture = capture->next;
 
- 	}
 
- }
 
- extern "C" EXPORT void winrt_capture_thread_stop()
 
- {
 
- 	struct winrt_capture *capture = capture_list;
 
- 	while (capture) {
 
- 		winrt_capture_device_loss_release(capture);
 
- 		capture = capture->next;
 
- 	}
 
- }
 
 
  |