|
@@ -68,8 +68,8 @@ enum display_capture_method {
|
|
|
struct duplicator_capture {
|
|
|
obs_source_t *source;
|
|
|
pthread_mutex_t update_mutex;
|
|
|
- int monitor;
|
|
|
- int dxgi_index;
|
|
|
+ char monitor_id[128];
|
|
|
+ char monitor_name[64];
|
|
|
enum display_capture_method method;
|
|
|
bool reset_wgc;
|
|
|
HMONITOR handle;
|
|
@@ -93,9 +93,8 @@ struct duplicator_capture {
|
|
|
};
|
|
|
|
|
|
struct wgc_monitor_info {
|
|
|
- int cur_id;
|
|
|
- int desired_id;
|
|
|
- int id;
|
|
|
+ char device_id[128];
|
|
|
+ char name[64];
|
|
|
RECT rect;
|
|
|
HMONITOR handle;
|
|
|
};
|
|
@@ -117,49 +116,128 @@ static const char *get_method_name(int method)
|
|
|
return method_name;
|
|
|
}
|
|
|
|
|
|
+static bool GetMonitorTarget(LPCWSTR device,
|
|
|
+ DISPLAYCONFIG_TARGET_DEVICE_NAME *target)
|
|
|
+{
|
|
|
+ bool found = false;
|
|
|
+
|
|
|
+ UINT32 numPath, numMode;
|
|
|
+ if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath,
|
|
|
+ &numMode) == ERROR_SUCCESS) {
|
|
|
+ DISPLAYCONFIG_PATH_INFO *paths =
|
|
|
+ bmalloc(numPath * sizeof(DISPLAYCONFIG_PATH_INFO));
|
|
|
+ DISPLAYCONFIG_MODE_INFO *modes =
|
|
|
+ bmalloc(numMode * sizeof(DISPLAYCONFIG_MODE_INFO));
|
|
|
+ if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPath, paths,
|
|
|
+ &numMode, modes,
|
|
|
+ NULL) == ERROR_SUCCESS) {
|
|
|
+ for (size_t i = 0; i < numPath; ++i) {
|
|
|
+ const DISPLAYCONFIG_PATH_INFO *const path =
|
|
|
+ &paths[i];
|
|
|
+
|
|
|
+ DISPLAYCONFIG_SOURCE_DEVICE_NAME
|
|
|
+ source;
|
|
|
+ source.header.type =
|
|
|
+ DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
|
|
|
+ source.header.size = sizeof(source);
|
|
|
+ source.header.adapterId =
|
|
|
+ path->sourceInfo.adapterId;
|
|
|
+ source.header.id = path->sourceInfo.id;
|
|
|
+ if (DisplayConfigGetDeviceInfo(
|
|
|
+ &source.header) == ERROR_SUCCESS &&
|
|
|
+ wcscmp(device, source.viewGdiDeviceName) ==
|
|
|
+ 0) {
|
|
|
+ target->header.type =
|
|
|
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
|
|
|
+ target->header.size = sizeof(*target);
|
|
|
+ target->header.adapterId =
|
|
|
+ path->sourceInfo.adapterId;
|
|
|
+ target->header.id = path->targetInfo.id;
|
|
|
+ found = DisplayConfigGetDeviceInfo(
|
|
|
+ &target->header) ==
|
|
|
+ ERROR_SUCCESS;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bfree(modes);
|
|
|
+ bfree(paths);
|
|
|
+ }
|
|
|
+
|
|
|
+ return found;
|
|
|
+}
|
|
|
+
|
|
|
+static void GetMonitorName(HMONITOR handle, char *name, size_t count)
|
|
|
+{
|
|
|
+ MONITORINFOEXW mi;
|
|
|
+ DISPLAYCONFIG_TARGET_DEVICE_NAME target;
|
|
|
+
|
|
|
+ mi.cbSize = sizeof(mi);
|
|
|
+ if (GetMonitorInfoW(handle, (LPMONITORINFO)&mi) &&
|
|
|
+ GetMonitorTarget(mi.szDevice, &target)) {
|
|
|
+ snprintf(name, count, "%ls", target.monitorFriendlyDeviceName);
|
|
|
+ } else {
|
|
|
+ strcpy_s(name, count, "[OBS: Unknown]");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static BOOL CALLBACK enum_monitor(HMONITOR handle, HDC hdc, LPRECT rect,
|
|
|
LPARAM param)
|
|
|
{
|
|
|
+ UNUSED_PARAMETER(hdc);
|
|
|
+
|
|
|
struct wgc_monitor_info *monitor = (struct wgc_monitor_info *)param;
|
|
|
|
|
|
- if (monitor->cur_id == 0 || monitor->desired_id == monitor->cur_id) {
|
|
|
- monitor->id = monitor->cur_id;
|
|
|
- monitor->rect = *rect;
|
|
|
- monitor->handle = handle;
|
|
|
+ bool match = false;
|
|
|
+
|
|
|
+ MONITORINFOEXA mi;
|
|
|
+ mi.cbSize = sizeof(mi);
|
|
|
+ if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) {
|
|
|
+ DISPLAY_DEVICEA device;
|
|
|
+ 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;
|
|
|
+ if (match) {
|
|
|
+ monitor->rect = *rect;
|
|
|
+ monitor->handle = handle;
|
|
|
+ GetMonitorName(handle, monitor->name,
|
|
|
+ _countof(monitor->name));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- UNUSED_PARAMETER(hdc);
|
|
|
- return (monitor->desired_id > monitor->cur_id++);
|
|
|
+ return !match;
|
|
|
}
|
|
|
|
|
|
-static void log_settings(struct duplicator_capture *capture, int monitor,
|
|
|
- LONG width, LONG height)
|
|
|
+static void log_settings(struct duplicator_capture *capture,
|
|
|
+ const char *monitor, LONG width, LONG height)
|
|
|
{
|
|
|
info("update settings:\n"
|
|
|
- "\tdisplay: %d (%ldx%ld)\n"
|
|
|
+ "\tdisplay: %s (%ldx%ld)\n"
|
|
|
"\tcursor: %s\n"
|
|
|
"\tmethod: %s",
|
|
|
- monitor + 1, width, height,
|
|
|
- capture->capture_cursor ? "true" : "false",
|
|
|
+ monitor, width, height, capture->capture_cursor ? "true" : "false",
|
|
|
get_method_name(capture->method));
|
|
|
}
|
|
|
|
|
|
static enum display_capture_method
|
|
|
choose_method(enum display_capture_method method, bool wgc_supported,
|
|
|
- HMONITOR monitor, int *dxgi_index)
|
|
|
+ HMONITOR monitor)
|
|
|
{
|
|
|
if (!wgc_supported)
|
|
|
method = METHOD_DXGI;
|
|
|
|
|
|
- if (method != METHOD_WGC) {
|
|
|
+ if (method == METHOD_AUTO) {
|
|
|
+ method = METHOD_DXGI;
|
|
|
+
|
|
|
obs_enter_graphics();
|
|
|
- *dxgi_index = gs_duplicator_get_monitor_index(monitor);
|
|
|
+ const int dxgi_index = gs_duplicator_get_monitor_index(monitor);
|
|
|
obs_leave_graphics();
|
|
|
- }
|
|
|
|
|
|
- if (method == METHOD_AUTO) {
|
|
|
- method = METHOD_DXGI;
|
|
|
- if (*dxgi_index == -1) {
|
|
|
+ if (dxgi_index == -1) {
|
|
|
method = METHOD_WGC;
|
|
|
} else {
|
|
|
SYSTEM_POWER_STATUS status;
|
|
@@ -185,14 +263,18 @@ static inline void update_settings(struct duplicator_capture *capture,
|
|
|
pthread_mutex_lock(&capture->update_mutex);
|
|
|
|
|
|
struct wgc_monitor_info monitor = {0};
|
|
|
- monitor.desired_id = (int)obs_data_get_int(settings, "monitor");
|
|
|
+ strcpy_s(monitor.device_id, _countof(monitor.device_id),
|
|
|
+ obs_data_get_string(settings, "monitor_id"));
|
|
|
EnumDisplayMonitors(NULL, NULL, enum_monitor, (LPARAM)&monitor);
|
|
|
|
|
|
- capture->method = choose_method(
|
|
|
- (int)obs_data_get_int(settings, "method"), wgc_supported,
|
|
|
- monitor.handle, &capture->dxgi_index);
|
|
|
+ capture->method =
|
|
|
+ choose_method((int)obs_data_get_int(settings, "method"),
|
|
|
+ wgc_supported, monitor.handle);
|
|
|
|
|
|
- capture->monitor = monitor.id;
|
|
|
+ strcpy_s(capture->monitor_id, _countof(capture->monitor_id),
|
|
|
+ monitor.device_id);
|
|
|
+ strcpy_s(capture->monitor_name, _countof(capture->monitor_name),
|
|
|
+ monitor.name);
|
|
|
capture->handle = monitor.handle;
|
|
|
|
|
|
capture->capture_cursor = obs_data_get_bool(settings, "capture_cursor");
|
|
@@ -266,7 +348,7 @@ static void duplicator_capture_destroy(void *data)
|
|
|
static void duplicator_capture_defaults(obs_data_t *settings)
|
|
|
{
|
|
|
obs_data_set_default_int(settings, "method", METHOD_AUTO);
|
|
|
- obs_data_set_default_int(settings, "monitor", 0);
|
|
|
+ obs_data_set_default_string(settings, "monitor_id", "DUMMY");
|
|
|
obs_data_set_default_int(settings, "monitor_wgc", 0);
|
|
|
obs_data_set_default_bool(settings, "capture_cursor", true);
|
|
|
}
|
|
@@ -275,7 +357,7 @@ static void duplicator_capture_update(void *data, obs_data_t *settings)
|
|
|
{
|
|
|
struct duplicator_capture *mc = data;
|
|
|
update_settings(mc, settings);
|
|
|
- log_settings(mc, mc->monitor, mc->logged_width, mc->logged_height);
|
|
|
+ log_settings(mc, mc->monitor_name, mc->logged_width, mc->logged_height);
|
|
|
|
|
|
mc->reset_wgc = true;
|
|
|
}
|
|
@@ -332,7 +414,7 @@ static void *duplicator_capture_create(obs_data_t *settings,
|
|
|
}
|
|
|
|
|
|
update_settings(capture, settings);
|
|
|
- log_settings(capture, capture->monitor, capture->logged_width,
|
|
|
+ log_settings(capture, capture->monitor_name, capture->logged_width,
|
|
|
capture->logged_height);
|
|
|
|
|
|
return capture;
|
|
@@ -343,7 +425,8 @@ static void reset_capture_data(struct duplicator_capture *capture)
|
|
|
struct gs_monitor_info monitor_info = {0};
|
|
|
gs_texture_t *texture = gs_duplicator_get_texture(capture->duplicator);
|
|
|
|
|
|
- gs_get_duplicator_monitor_info(capture->dxgi_index, &monitor_info);
|
|
|
+ const int dxgi_index = gs_duplicator_get_monitor_index(capture->handle);
|
|
|
+ gs_get_duplicator_monitor_info(dxgi_index, &monitor_info);
|
|
|
if (texture) {
|
|
|
capture->width = gs_texture_get_width(texture);
|
|
|
capture->height = gs_texture_get_height(texture);
|
|
@@ -378,6 +461,15 @@ static void free_capture_data(struct duplicator_capture *capture)
|
|
|
capture->reset_timeout = 0.0f;
|
|
|
}
|
|
|
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
static void duplicator_capture_tick(void *data, float seconds)
|
|
|
{
|
|
|
struct duplicator_capture *capture = data;
|
|
@@ -416,13 +508,27 @@ static void duplicator_capture_tick(void *data, float seconds)
|
|
|
capture->reset_timeout += seconds;
|
|
|
|
|
|
if (capture->reset_timeout >= RESET_INTERVAL_SEC) {
|
|
|
- capture->capture_winrt =
|
|
|
- capture->exports
|
|
|
- .winrt_capture_init_monitor(
|
|
|
+ if (!capture->handle)
|
|
|
+ update_monitor_handle(capture);
|
|
|
+
|
|
|
+ if (capture->handle) {
|
|
|
+ capture->capture_winrt =
|
|
|
+ capture->exports.winrt_capture_init_monitor(
|
|
|
capture->capture_cursor,
|
|
|
capture->handle);
|
|
|
-
|
|
|
- capture->reset_timeout = 0.0f;
|
|
|
+ if (!capture->capture_winrt) {
|
|
|
+ update_monitor_handle(capture);
|
|
|
+
|
|
|
+ if (capture->handle) {
|
|
|
+ capture->capture_winrt =
|
|
|
+ capture->exports.winrt_capture_init_monitor(
|
|
|
+ capture->capture_cursor,
|
|
|
+ capture->handle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ capture->reset_timeout = 0.0f;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
@@ -436,10 +542,31 @@ static void duplicator_capture_tick(void *data, float seconds)
|
|
|
capture->reset_timeout += seconds;
|
|
|
|
|
|
if (capture->reset_timeout >= RESET_INTERVAL_SEC) {
|
|
|
- capture->duplicator = gs_duplicator_create(
|
|
|
- capture->dxgi_index);
|
|
|
+ if (!capture->handle)
|
|
|
+ update_monitor_handle(capture);
|
|
|
|
|
|
- capture->reset_timeout = 0.0f;
|
|
|
+ if (capture->handle) {
|
|
|
+ int dxgi_index =
|
|
|
+ gs_duplicator_get_monitor_index(
|
|
|
+ capture->handle);
|
|
|
+
|
|
|
+ if (dxgi_index == -1) {
|
|
|
+ update_monitor_handle(capture);
|
|
|
+
|
|
|
+ if (capture->handle) {
|
|
|
+ dxgi_index = gs_duplicator_get_monitor_index(
|
|
|
+ capture->handle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dxgi_index != -1) {
|
|
|
+ capture->duplicator =
|
|
|
+ gs_duplicator_create(
|
|
|
+ dxgi_index);
|
|
|
+
|
|
|
+ capture->reset_timeout = 0.0f;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -600,38 +727,42 @@ static BOOL CALLBACK enum_monitor_props(HMONITOR handle, HDC hdc, LPRECT rect,
|
|
|
UNUSED_PARAMETER(hdc);
|
|
|
UNUSED_PARAMETER(rect);
|
|
|
|
|
|
- obs_property_t *monitor_list = (obs_property_t *)param;
|
|
|
- MONITORINFO mi;
|
|
|
- size_t monitor_id = 0;
|
|
|
- struct dstr monitor_desc = {0};
|
|
|
- struct dstr resolution = {0};
|
|
|
- struct dstr format_string = {0};
|
|
|
-
|
|
|
- monitor_id = obs_property_list_item_count(monitor_list);
|
|
|
-
|
|
|
+ MONITORINFOEXA mi;
|
|
|
mi.cbSize = sizeof(mi);
|
|
|
- GetMonitorInfo(handle, &mi);
|
|
|
+ if (GetMonitorInfoA(handle, (LPMONITORINFO)&mi)) {
|
|
|
+ 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);
|
|
|
+ }
|
|
|
|
|
|
- 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);
|
|
|
+ obs_property_list_add_string(monitor_list,
|
|
|
+ monitor_desc.array,
|
|
|
+ device.DeviceID);
|
|
|
|
|
|
- dstr_copy(&format_string, "%s %d: %s");
|
|
|
- if (mi.dwFlags == MONITORINFOF_PRIMARY) {
|
|
|
- dstr_catf(&format_string, " (%s)", TEXT_PRIMARY_MONITOR);
|
|
|
+ dstr_free(&monitor_desc);
|
|
|
+ dstr_free(&resolution);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- dstr_catf(&monitor_desc, format_string.array, TEXT_MONITOR,
|
|
|
- monitor_id + 1, resolution.array);
|
|
|
-
|
|
|
- obs_property_list_add_int(monitor_list, monitor_desc.array,
|
|
|
- (int)monitor_id);
|
|
|
-
|
|
|
- dstr_free(&monitor_desc);
|
|
|
- dstr_free(&resolution);
|
|
|
- dstr_free(&format_string);
|
|
|
-
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
@@ -689,8 +820,8 @@ static obs_properties_t *duplicator_capture_properties(void *data)
|
|
|
obs_property_set_modified_callback(p, display_capture_method_changed);
|
|
|
|
|
|
obs_property_t *monitors = obs_properties_add_list(
|
|
|
- props, "monitor", TEXT_MONITOR, OBS_COMBO_TYPE_LIST,
|
|
|
- OBS_COMBO_FORMAT_INT);
|
|
|
+ props, "monitor_id", TEXT_MONITOR, OBS_COMBO_TYPE_LIST,
|
|
|
+ OBS_COMBO_FORMAT_STRING);
|
|
|
|
|
|
obs_properties_add_bool(props, "capture_cursor", TEXT_CAPTURE_CURSOR);
|
|
|
|