From cce9fb7f9577cfcf63b8702ba4c246cbf55a8179 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Mon, 24 Feb 2020 19:42:46 -0800 Subject: [PATCH 1/2] win-capture: Hide settings if Automatic is WGC --- plugins/win-capture/window-capture.c | 135 +++++++++++++++------------ 1 file changed, 76 insertions(+), 59 deletions(-) diff --git a/plugins/win-capture/window-capture.c b/plugins/win-capture/window-capture.c index f7bc4a3a8..631eedd0b 100644 --- a/plugins/win-capture/window-capture.c +++ b/plugins/win-capture/window-capture.c @@ -48,7 +48,6 @@ struct window_capture { char *executable; enum window_capture_method method; enum window_priority priority; - bool auto_choose_method; bool cursor; bool compatibility; bool use_wildcards; /* TODO */ @@ -68,6 +67,53 @@ struct window_capture { RECT last_rect; }; +static const char *wgc_partial_match_classes[] = { + "Chrome", + "Mozilla", + NULL, +}; + +static const char *wgc_whole_match_classes[] = { + "ApplicationFrameWindow", + "Windows.UI.Core.CoreWindow", + "XLMAIN", /* excel*/ + "PPTFrameClass", /* powerpoint */ + "OpusApp", /* word */ + NULL, +}; + +static enum window_capture_method +choose_method(enum window_capture_method method, bool wgc_supported, + const char *current_class) +{ + if (method != METHOD_AUTO) { + if (method == METHOD_WGC && !wgc_supported) + method = METHOD_BITBLT; + return method; + } + + if (!current_class) + return METHOD_BITBLT; + + const char **class = wgc_partial_match_classes; + while (*class) { + if (astrstri(current_class, *class) != NULL) { + return METHOD_WGC; + } + class ++; + } + + class = wgc_whole_match_classes; + while (*class) { + if (astrcmpi(current_class, *class) == 0) { + return METHOD_WGC; + } + class ++; + } + + return METHOD_BITBLT; +} + static void update_settings(struct window_capture *wc, obs_data_t *s) { int method = (int)obs_data_get_int(s, "method"); @@ -88,13 +134,8 @@ static void update_settings(struct window_capture *wc, obs_data_t *s) blog(LOG_DEBUG, "\tclass: %s", wc->class); } - if (!wc->wgc_supported) { - method = METHOD_BITBLT; - } - - wc->method = method; + wc->method = choose_method(method, wc->wgc_supported, wc->class); wc->priority = (enum window_priority)priority; - wc->auto_choose_method = (method == METHOD_AUTO); wc->cursor = obs_data_get_bool(s, "cursor"); wc->use_wildcards = obs_data_get_bool(s, "use_wildcards"); wc->compatibility = obs_data_get_bool(s, "compatibility"); @@ -213,17 +254,36 @@ static void wc_defaults(obs_data_t *defaults) obs_data_set_default_bool(defaults, "compatibility", false); } +static void update_settings_visibility(obs_properties_t *props, + enum window_capture_method method) +{ + const bool bitblt_options = method == METHOD_BITBLT; + + obs_property_t *p = obs_properties_get(props, "cursor"); + obs_property_set_visible(p, bitblt_options); + + p = obs_properties_get(props, "compatibility"); + obs_property_set_visible(p, bitblt_options); +} + static bool wc_capture_method_changed(obs_properties_t *props, obs_property_t *p, obs_data_t *settings) { - const int method = (int)obs_data_get_int(settings, "method"); - const bool show_options = method != METHOD_WGC; + struct window_capture *wc = obs_properties_get_param(props); + update_settings(wc, settings); - p = obs_properties_get(props, "cursor"); - obs_property_set_visible(p, show_options); + update_settings_visibility(props, wc->method); - p = obs_properties_get(props, "compatibility"); - obs_property_set_visible(p, show_options); + return true; +} + +static bool wc_window_changed(obs_properties_t *props, obs_property_t *p, + obs_data_t *settings) +{ + struct window_capture *wc = obs_properties_get_param(props); + update_settings(wc, settings); + + update_settings_visibility(props, wc->method); return true; } @@ -233,6 +293,8 @@ static obs_properties_t *wc_properties(void *data) struct window_capture *wc = data; obs_properties_t *ppts = obs_properties_create(); + obs_properties_set_param(ppts, wc, NULL); + obs_property_t *p; p = obs_properties_add_list(ppts, "method", TEXT_METHOD, @@ -247,6 +309,7 @@ static obs_properties_t *wc_properties(void *data) OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); fill_window_list(p, EXCLUDE_MINIMIZED, NULL); + obs_property_set_modified_callback(p, wc_window_changed); p = obs_properties_add_list(ppts, "priority", TEXT_MATCH_PRIORITY, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); @@ -273,48 +336,6 @@ static void wc_hide(void *data) memset(&wc->last_rect, 0, sizeof(wc->last_rect)); } -static const char *wgc_partial_match_classes[] = { - "Chrome", - "Mozilla", - NULL, -}; - -static const char *wgc_whole_match_classes[] = { - "ApplicationFrameWindow", - "Windows.UI.Core.CoreWindow", - "XLMAIN", /* excel*/ - "PPTFrameClass", /* powerpoint */ - "OpusApp", /* word */ - NULL, -}; - -static void auto_choose_method(struct window_capture *wc) -{ - wc->method = METHOD_BITBLT; - - if (!wc->class) { - return; - } - - const char **class = wgc_partial_match_classes; - while (*class) { - if (astrstri(wc->class, *class) != NULL) { - wc->method = METHOD_WGC; - return; - } - class ++; - } - - class = wgc_whole_match_classes; - while (*class) { - if (astrcmpi(wc->class, *class) == 0) { - wc->method = METHOD_WGC; - return; - } - class ++; - } -} - #define RESIZE_CHECK_TIME 0.2f #define CURSOR_CHECK_TIME 0.2f @@ -344,10 +365,6 @@ static void wc_tick(void *data, float seconds) wc->capture_winrt = NULL; } - if (wc->auto_choose_method) { - auto_choose_method(wc); - } - wc->check_window_timer = 0.0f; wc->window = (wc->method == METHOD_WGC) From 2111a3a02fa136711b1aae859d1f70ac72e9d524 Mon Sep 17 00:00:00 2001 From: jpark37 Date: Mon, 24 Feb 2020 21:21:52 -0800 Subject: [PATCH 2/2] libobs-winrt: win-capture: Support client area toggle for WGC --- libobs-winrt/CMakeLists.txt | 2 + libobs-winrt/winrt-capture.cpp | 110 ++++++++++++++++++---- libobs-winrt/winrt-capture.h | 7 +- plugins/win-capture/data/locale/en-US.ini | 1 + plugins/win-capture/window-capture.c | 19 +++- 5 files changed, 116 insertions(+), 23 deletions(-) diff --git a/libobs-winrt/CMakeLists.txt b/libobs-winrt/CMakeLists.txt index f6a88326c..1739fd50f 100644 --- a/libobs-winrt/CMakeLists.txt +++ b/libobs-winrt/CMakeLists.txt @@ -24,11 +24,13 @@ target_precompile_headers(libobs-winrt [["../libobs/util/windows/ComPtr.hpp"]] + ) target_link_libraries(libobs-winrt libobs + Dwmapi windowsapp) install_obs_core(libobs-winrt) diff --git a/libobs-winrt/winrt-capture.cpp b/libobs-winrt/winrt-capture.cpp index b426d1a16..7fb6a68ce 100644 --- a/libobs-winrt/winrt-capture.cpp +++ b/libobs-winrt/winrt-capture.cpp @@ -31,8 +31,56 @@ static winrt::com_ptr GetDXGIInterfaceFromObject( 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{}; + + const bool client_box_available = + GetClientRect(window, &client_rect) && + (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; + } + + return client_box_available; +} + struct winrt_capture { bool capture_cursor; + HWND window; + bool client_area; gs_texture_t *texture; bool texture_written; @@ -48,6 +96,11 @@ struct winrt_capture { winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool:: FrameArrived_revoker frame_arrived; + uint32_t texture_width; + uint32_t texture_height; + D3D11_BOX client_box; + bool client_box_available; + bool thread_changed; struct winrt_capture *next; @@ -70,23 +123,45 @@ struct winrt_capture { D3D11_TEXTURE2D_DESC desc; frame_surface->GetDesc(&desc); + client_box_available = false; + if (client_area) { + client_box_available = get_client_box( + window, desc.Width, desc.Height, &client_box); + } + + if (client_box_available) { + 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 (desc.Width != gs_texture_get_width(texture) || - desc.Height != gs_texture_get_height(texture)) { + if (texture_width != gs_texture_get_width(texture) || + texture_height != gs_texture_get_height(texture)) { gs_texture_destroy(texture); texture = nullptr; } } if (!texture) { - texture = gs_texture_create(desc.Width, desc.Height, - GS_BGRA, 1, nullptr, 0); + texture = gs_texture_create(texture_width, + texture_height, GS_BGRA, 1, + nullptr, 0); } - /* if they gave an SRV, we could avoid this copy */ - context->CopyResource( - (ID3D11Texture2D *)gs_texture_get_obj(texture), - frame_surface.get()); + if (client_box_available) { + 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; @@ -160,8 +235,8 @@ static void winrt_capture_device_loss_rebuild(void *device_void, void *data) thread_local bool initialized_tls; -extern "C" EXPORT struct winrt_capture *winrt_capture_init(bool cursor, - HWND window) +extern "C" EXPORT struct winrt_capture * +winrt_capture_init(bool cursor, HWND window, bool client_area) { ID3D11Device *const d3d_device = (ID3D11Device *)gs_get_device_obj(); ComPtr dxgi_device; @@ -192,8 +267,9 @@ extern "C" EXPORT struct winrt_capture *winrt_capture_init(bool cursor, IGraphicsCaptureItem>(), reinterpret_cast(winrt::put_abi(item))); } catch (winrt::hresult_invalid_argument &) { - blog(LOG_WARNING, "[winrt_capture_init] Failed to " - "create GraphicsCaptureItem"); + /* too spammy */ + //blog(LOG_WARNING, "[winrt_capture_init] Failed to " + // "create GraphicsCaptureItem"); return nullptr; } @@ -216,6 +292,8 @@ extern "C" EXPORT struct winrt_capture *winrt_capture_init(bool cursor, struct winrt_capture *capture = new winrt_capture{}; capture->capture_cursor = cursor; + capture->window = window; + capture->client_area = client_area; capture->item = item; capture->device = device; d3d_device->GetImmediateContext(&capture->context); @@ -315,14 +393,14 @@ extern "C" EXPORT void winrt_capture_render(struct winrt_capture *capture, } } -extern "C" EXPORT int32_t +extern "C" EXPORT uint32_t winrt_capture_width(const struct winrt_capture *capture) { - return capture ? capture->last_size.Width : 0; + return capture ? capture->texture_width : 0; } -extern "C" EXPORT int32_t +extern "C" EXPORT uint32_t winrt_capture_height(const struct winrt_capture *capture) { - return capture ? capture->last_size.Height : 0; + return capture ? capture->texture_height : 0; } diff --git a/libobs-winrt/winrt-capture.h b/libobs-winrt/winrt-capture.h index a42e05579..ae5cefb1f 100644 --- a/libobs-winrt/winrt-capture.h +++ b/libobs-winrt/winrt-capture.h @@ -10,13 +10,14 @@ extern "C" { #endif EXPORT bool winrt_capture_supported(); -EXPORT struct winrt_capture *winrt_capture_init(bool cursor, HWND window); +EXPORT struct winrt_capture *winrt_capture_init(bool cursor, HWND window, + bool client_area); EXPORT void winrt_capture_free(struct winrt_capture *capture); EXPORT void winrt_capture_render(struct winrt_capture *capture, gs_effect_t *effect); -EXPORT int32_t winrt_capture_width(const struct winrt_capture *capture); -EXPORT int32_t winrt_capture_height(const struct winrt_capture *capture); +EXPORT uint32_t winrt_capture_width(const struct winrt_capture *capture); +EXPORT uint32_t winrt_capture_height(const struct winrt_capture *capture); #ifdef __cplusplus } diff --git a/plugins/win-capture/data/locale/en-US.ini b/plugins/win-capture/data/locale/en-US.ini index 9c517e5aa..a8aae008c 100644 --- a/plugins/win-capture/data/locale/en-US.ini +++ b/plugins/win-capture/data/locale/en-US.ini @@ -11,6 +11,7 @@ WindowCapture.Priority.Class="Match title, otherwise find window of same type" WindowCapture.Priority.Exe="Match title, otherwise find window of same executable" CaptureCursor="Capture Cursor" Compatibility="Multi-adapter Compatibility" +ClientArea="Client Area" SLIFix="SLI/Crossfire Capture Mode (Slow)" AllowTransparency="Allow Transparency" Monitor="Display" diff --git a/plugins/win-capture/window-capture.c b/plugins/win-capture/window-capture.c index 631eedd0b..9e43aee05 100644 --- a/plugins/win-capture/window-capture.c +++ b/plugins/win-capture/window-capture.c @@ -19,6 +19,7 @@ #define TEXT_MATCH_EXE obs_module_text("WindowCapture.Priority.Exe") #define TEXT_CAPTURE_CURSOR obs_module_text("CaptureCursor") #define TEXT_COMPATIBILITY obs_module_text("Compatibility") +#define TEXT_CLIENT_AREA obs_module_text("ClientArea") /* clang-format on */ @@ -26,12 +27,13 @@ struct winrt_exports { bool *(*winrt_capture_supported)(); - struct winrt_capture *(*winrt_capture_init)(bool cursor, HWND window); + struct winrt_capture *(*winrt_capture_init)(bool cursor, HWND window, + bool client_area); void (*winrt_capture_free)(struct winrt_capture *capture); void (*winrt_capture_render)(struct winrt_capture *capture, gs_effect_t *effect); - int32_t (*winrt_capture_width)(const struct winrt_capture *capture); - int32_t (*winrt_capture_height)(const struct winrt_capture *capture); + uint32_t (*winrt_capture_width)(const struct winrt_capture *capture); + uint32_t (*winrt_capture_height)(const struct winrt_capture *capture); }; enum window_capture_method { @@ -50,6 +52,7 @@ struct window_capture { enum window_priority priority; bool cursor; bool compatibility; + bool client_area; bool use_wildcards; /* TODO */ struct dc_capture capture; @@ -139,6 +142,7 @@ static void update_settings(struct window_capture *wc, obs_data_t *s) wc->cursor = obs_data_get_bool(s, "cursor"); wc->use_wildcards = obs_data_get_bool(s, "use_wildcards"); wc->compatibility = obs_data_get_bool(s, "compatibility"); + wc->client_area = obs_data_get_bool(s, "client_area"); } /* ------------------------------------------------------------------------- */ @@ -252,18 +256,23 @@ static void wc_defaults(obs_data_t *defaults) obs_data_set_default_int(defaults, "method", METHOD_AUTO); obs_data_set_default_bool(defaults, "cursor", true); obs_data_set_default_bool(defaults, "compatibility", false); + obs_data_set_default_bool(defaults, "client_area", true); } static void update_settings_visibility(obs_properties_t *props, enum window_capture_method method) { const bool bitblt_options = method == METHOD_BITBLT; + const bool wgc_options = method == METHOD_WGC; obs_property_t *p = obs_properties_get(props, "cursor"); obs_property_set_visible(p, bitblt_options); p = obs_properties_get(props, "compatibility"); obs_property_set_visible(p, bitblt_options); + + p = obs_properties_get(props, "client_area"); + obs_property_set_visible(p, wgc_options); } static bool wc_capture_method_changed(obs_properties_t *props, @@ -321,6 +330,8 @@ static obs_properties_t *wc_properties(void *data) obs_properties_add_bool(ppts, "compatibility", TEXT_COMPATIBILITY); + obs_properties_add_bool(ppts, "client_area", TEXT_CLIENT_AREA); + return ppts; } @@ -441,7 +452,7 @@ static void wc_tick(void *data, float seconds) } else if (wc->method == METHOD_WGC) { if (wc->window && (wc->capture_winrt == NULL)) { wc->capture_winrt = wc->exports.winrt_capture_init( - wc->cursor, wc->window); + wc->cursor, wc->window, wc->client_area); } }