Browse Source

win-capture: Add 'auto' method to window capture

Adds an "Automatic" method to the capture method property of window
capture.  This allows the ability for window capture to automatically
determine the best capture method to use.  Primarily, it prefers BitBlt
in most cases, but will use WGC when it detects the window is a browser,
microsoft office, or a UWP program.

This was implemented because the new capture method has a number of
undesired effects associated with it -- the issue of the capture border
that we can do nothing about, the fact that we can't control the capture
of the cursor, and the fact that Microsoft designed it to switch the
cursor away from hardware cursor mode when the capture is active (there
was absolutely no reason to do this because even OBS can capture the
hardware cursor with no issue).  Until we get a new version of this API
that doesn't absolutely blow, we're stuck preferring BitBlt instead.

But hey, at least people will be able to capture browser windows now.
jp9000 5 years ago
parent
commit
572ce73115
2 changed files with 58 additions and 5 deletions
  1. 1 0
      plugins/win-capture/data/locale/en-US.ini
  2. 57 5
      plugins/win-capture/window-capture.c

+ 1 - 0
plugins/win-capture/data/locale/en-US.ini

@@ -2,6 +2,7 @@ MonitorCapture="Display Capture"
 WindowCapture="Window Capture"
 WindowCapture.Window="Window"
 WindowCapture.Method="Capture Method"
+WindowCapture.Method.Auto="Automatic"
 WindowCapture.Method.BitBlt="BitBlt (Windows 7 and up)"
 WindowCapture.Method.WindowsGraphicsCapture="Windows Graphics Capture (Windows 10 1903 and up)"
 WindowCapture.Priority="Window Match Priority"

+ 57 - 5
plugins/win-capture/window-capture.c

@@ -10,6 +10,7 @@
 #define TEXT_WINDOW_CAPTURE obs_module_text("WindowCapture")
 #define TEXT_WINDOW         obs_module_text("WindowCapture.Window")
 #define TEXT_METHOD         obs_module_text("WindowCapture.Method")
+#define TEXT_METHOD_AUTO    obs_module_text("WindowCapture.Method.Auto")
 #define TEXT_METHOD_BITBLT  obs_module_text("WindowCapture.Method.BitBlt")
 #define TEXT_METHOD_WGC     obs_module_text("WindowCapture.Method.WindowsGraphicsCapture")
 #define TEXT_MATCH_PRIORITY obs_module_text("WindowCapture.Priority")
@@ -34,6 +35,7 @@ struct winrt_exports {
 };
 
 enum window_capture_method {
+	METHOD_AUTO,
 	METHOD_BITBLT,
 	METHOD_WGC,
 };
@@ -46,6 +48,7 @@ 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 */
@@ -85,11 +88,13 @@ static void update_settings(struct window_capture *wc, obs_data_t *s)
 		blog(LOG_DEBUG, "\tclass:      %s", wc->class);
 	}
 
-	if ((method == METHOD_WGC) && !wc->wgc_supported)
+	if (!wc->wgc_supported) {
 		method = METHOD_BITBLT;
+	}
 
 	wc->method = method;
 	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");
@@ -203,7 +208,7 @@ static uint32_t wc_height(void *data)
 
 static void wc_defaults(obs_data_t *defaults)
 {
-	obs_data_set_default_int(defaults, "method", METHOD_BITBLT);
+	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);
 }
@@ -212,13 +217,13 @@ 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 use_bitblt = method == METHOD_BITBLT;
+	const bool show_options = method != METHOD_WGC;
 
 	p = obs_properties_get(props, "cursor");
-	obs_property_set_visible(p, use_bitblt);
+	obs_property_set_visible(p, show_options);
 
 	p = obs_properties_get(props, "compatibility");
-	obs_property_set_visible(p, use_bitblt);
+	obs_property_set_visible(p, show_options);
 
 	return true;
 }
@@ -232,6 +237,7 @@ static obs_properties_t *wc_properties(void *data)
 
 	p = obs_properties_add_list(ppts, "method", TEXT_METHOD,
 				    OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
+	obs_property_list_add_int(p, TEXT_METHOD_AUTO, METHOD_AUTO);
 	obs_property_list_add_int(p, TEXT_METHOD_BITBLT, METHOD_BITBLT);
 	obs_property_list_add_int(p, TEXT_METHOD_WGC, METHOD_WGC);
 	obs_property_list_item_disable(p, 1, !wc->wgc_supported);
@@ -267,6 +273,48 @@ 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
 
@@ -296,6 +344,10 @@ 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)