diff --git a/UI/context-bar-controls.cpp b/UI/context-bar-controls.cpp index bbe655ac5..ff6eda919 100644 --- a/UI/context-bar-controls.cpp +++ b/UI/context-bar-controls.cpp @@ -311,10 +311,12 @@ void DisplayCaptureToolbar::Init() const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); ui->deviceLabel->setText(device_str); +#ifndef _WIN32 is_int = true; +#endif #ifdef _WIN32 - prop_name = "monitor"; + prop_name = "monitor_id"; #elif __APPLE__ prop_name = "display"; #else diff --git a/plugins/win-capture/duplicator-monitor-capture.c b/plugins/win-capture/duplicator-monitor-capture.c index e8a0904b0..3fd96eeea 100644 --- a/plugins/win-capture/duplicator-monitor-capture.c +++ b/plugins/win-capture/duplicator-monitor-capture.c @@ -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) { - obs_enter_graphics(); - *dxgi_index = gs_duplicator_get_monitor_index(monitor); - obs_leave_graphics(); - } - if (method == METHOD_AUTO) { method = METHOD_DXGI; - if (*dxgi_index == -1) { + + obs_enter_graphics(); + const int dxgi_index = gs_duplicator_get_monitor_index(monitor); + obs_leave_graphics(); + + 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); + if (!capture->capture_winrt) { + update_monitor_handle(capture); - capture->reset_timeout = 0.0f; + 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); + 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); - dstr_copy(&format_string, "%s %d: %s"); - if (mi.dwFlags == MONITORINFOF_PRIMARY) { - dstr_catf(&format_string, " (%s)", TEXT_PRIMARY_MONITOR); + 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); + } } - 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);