Browse Source

win-capture: Support EnumDisplayDevices failure

Seeing EnumDisplayDevices fail in the wild, so use GetMonitorInfo name
when the persistent name is unavailable.

(cherry picked from commit 0b30ff1debb24149d0d11079e6b92d675a00c51f)
jpark37 2 years ago
parent
commit
d66b9bd8e9
1 changed files with 70 additions and 36 deletions
  1. 70 36
      plugins/win-capture/duplicator-monitor-capture.c

+ 70 - 36
plugins/win-capture/duplicator-monitor-capture.c

@@ -92,7 +92,7 @@ struct duplicator_capture {
 	struct winrt_capture *capture_winrt;
 };
 
-struct wgc_monitor_info {
+struct duplicator_monitor_info {
 	char device_id[128];
 	char name[64];
 	RECT rect;
@@ -187,7 +187,8 @@ static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,
 {
 	UNUSED_PARAMETER(hdc);
 
-	struct wgc_monitor_info *monitor = (struct wgc_monitor_info *)param;
+	struct duplicator_monitor_info *monitor =
+		(struct duplicator_monitor_info *)param;
 
 	bool match = false;
 
@@ -198,8 +199,8 @@ static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,
 		device.cb = sizeof(device);
 		if (EnumDisplayDevicesA(mi.szDevice, 0, &device,
 					EDD_GET_DEVICE_INTERFACE_NAME)) {
-			const bool match = strcmp(monitor->device_id,
-						  device.DeviceID) == 0;
+			match = strcmp(monitor->device_id, device.DeviceID) ==
+				0;
 			if (match) {
 				monitor->rect = *rect;
 				monitor->handle = handle;
@@ -212,6 +213,31 @@ static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,
 	return !match;
 }
 
+static BOOL CALLBACK enum_monitor_fallback(HMONITOR handle, HDC hdc,
+					   LPRECT rect, LPARAM param)
+{
+	UNUSED_PARAMETER(hdc);
+
+	struct duplicator_monitor_info *monitor =
+		(struct duplicator_monitor_info *)param;
+
+	bool match = false;
+
+	MONITORINFOEXA mi;
+	mi.cbSize = sizeof(mi);
+	if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) {
+		match = strcmp(monitor->device_id, mi.szDevice) == 0;
+		if (match) {
+			monitor->rect = *rect;
+			monitor->handle = handle;
+			GetMonitorName(handle, monitor->name,
+				       _countof(monitor->name));
+		}
+	}
+
+	return !match;
+}
+
 static void log_settings(struct duplicator_capture *capture,
 			 const char *monitor, LONG width, LONG height)
 {
@@ -257,15 +283,26 @@ choose_method(enum display_capture_method method, bool wgc_supported,
 
 extern bool wgc_supported;
 
+static struct duplicator_monitor_info find_monitor(const char *monitor_id)
+{
+	struct duplicator_monitor_info monitor = {0};
+	strcpy_s(monitor.device_id, _countof(monitor.device_id), monitor_id);
+	EnumDisplayMonitors(NULL, NULL, &enum_monitor, (LPARAM)&monitor);
+	if (monitor.handle == NULL) {
+		EnumDisplayMonitors(NULL, NULL, &enum_monitor_fallback,
+				    (LPARAM)&monitor);
+	}
+
+	return monitor;
+}
+
 static inline void update_settings(struct duplicator_capture *capture,
 				   obs_data_t *settings)
 {
 	pthread_mutex_lock(&capture->update_mutex);
 
-	struct wgc_monitor_info monitor = {0};
-	strcpy_s(monitor.device_id, _countof(monitor.device_id),
-		 obs_data_get_string(settings, "monitor_id"));
-	EnumDisplayMonitors(NULL, NULL, enum_monitor, (LPARAM)&monitor);
+	struct duplicator_monitor_info monitor =
+		find_monitor(obs_data_get_string(settings, "monitor_id"));
 
 	capture->method =
 		choose_method((int)obs_data_get_int(settings, "method"),
@@ -463,11 +500,7 @@ static void free_capture_data(struct duplicator_capture *capture)
 
 static void update_monitor_handle(struct duplicator_capture *capture)
 {
-	struct wgc_monitor_info monitor = {0};
-	strcpy_s(monitor.device_id, _countof(monitor.device_id),
-		 capture->monitor_id);
-	EnumDisplayMonitors(NULL, NULL, enum_monitor, (LPARAM)&monitor);
-	capture->handle = monitor.handle;
+	capture->handle = find_monitor(capture->monitor_id).handle;
 }
 
 static void duplicator_capture_tick(void *data, float seconds)
@@ -727,40 +760,41 @@ static BOOL CALLBACK enum_monitor_props(HMONITOR handle, HDC hdc, LPRECT rect,
 	UNUSED_PARAMETER(hdc);
 	UNUSED_PARAMETER(rect);
 
+	char monitor_name[64];
+	GetMonitorName(handle, monitor_name, sizeof(monitor_name));
+
 	MONITORINFOEXA mi;
 	mi.cbSize = sizeof(mi);
 	if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) {
+		obs_property_t *monitor_list = (obs_property_t *)param;
+		struct dstr monitor_desc = {0};
+		dstr_printf(&monitor_desc, "%s: %dx%d @ %d,%d", monitor_name,
+			    mi.rcMonitor.right - mi.rcMonitor.left,
+			    mi.rcMonitor.bottom - mi.rcMonitor.top,
+			    mi.rcMonitor.left, mi.rcMonitor.top);
+		if (mi.dwFlags == MONITORINFOF_PRIMARY)
+			dstr_catf(&monitor_desc, " (%s)", TEXT_PRIMARY_MONITOR);
+
 		DISPLAY_DEVICEA device;
 		device.cb = sizeof(device);
 		if (EnumDisplayDevicesA(mi.szDevice, 0, &device,
 					EDD_GET_DEVICE_INTERFACE_NAME)) {
-			obs_property_t *monitor_list = (obs_property_t *)param;
-			struct dstr monitor_desc = {0};
-			struct dstr resolution = {0};
-
-			dstr_catf(&resolution, "%dx%d @ %d,%d",
-				  mi.rcMonitor.right - mi.rcMonitor.left,
-				  mi.rcMonitor.bottom - mi.rcMonitor.top,
-				  mi.rcMonitor.left, mi.rcMonitor.top);
-
-			char monitor_name[64];
-			GetMonitorName(handle, monitor_name,
-				       sizeof(monitor_name));
-			dstr_catf(&monitor_desc, "%s: %s", monitor_name,
-				  resolution.array);
-
-			if (mi.dwFlags == MONITORINFOF_PRIMARY) {
-				dstr_catf(&monitor_desc, " (%s)",
-					  TEXT_PRIMARY_MONITOR);
-			}
-
 			obs_property_list_add_string(monitor_list,
 						     monitor_desc.array,
 						     device.DeviceID);
-
-			dstr_free(&monitor_desc);
-			dstr_free(&resolution);
+		} else {
+			blog(LOG_WARNING,
+			     "[duplicator-monitor-capture] EnumDisplayDevices failed for monitor (%s), falling back to szDevice",
+			     monitor_name);
+			obs_property_list_add_string(
+				monitor_list, monitor_desc.array, mi.szDevice);
 		}
+
+		dstr_free(&monitor_desc);
+	} else {
+		blog(LOG_WARNING,
+		     "[duplicator-monitor-capture] GetMonitorInfo failed for monitor: %s",
+		     monitor_name);
 	}
 
 	return TRUE;