| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 | 
							- #include "winrt-capture.h"
 
- 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): %s", err.code().value,
 
- 	     winrt::to_string(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): %s", err.code().value,
 
- 	     winrt::to_string(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<Windows::Graphics::DirectX::Direct3D11::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 = std::min(width - left, (uint32_t)client_rect.right);
 
- 		}
 
- 		uint32_t texture_height = 1;
 
- 		if (height > top) {
 
- 			texture_height = std::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): %s", err.code().value,
 
- 		     winrt::to_string(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): %s", err.code().value,
 
- 		     winrt::to_string(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): %s", err.code().value,
 
- 	     winrt::to_string(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): %s", err.code().value,
 
- 			     winrt::to_string(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): %s", err.code().value,
 
- 			     winrt::to_string(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): %s", err.code().value, winrt::to_string(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): %s", err.code().value, winrt::to_string(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, BOOL force_sdr)
 
- {
 
- 	return winrt_capture_init_internal(cursor, NULL, false, force_sdr, 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): %s", err.code().value,
 
- 			     winrt::to_string(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): %s", err.code().value,
 
- 			     winrt::to_string(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): %s", err.code().value,
 
- 		     winrt::to_string(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;
 
- 	}
 
- }
 
 
  |