mirror of https://github.com/Xaymar/obs-StreamFX
obs/source-tracker: Fix leaked source references
This functionality broke at some point in the past without anyone noticing, resulting in most dropdowns that rely on this functionality being blank. Fixes #1025
This commit is contained in:
parent
5e307a8e36
commit
e8ec23c4d4
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2017-2018 Michael Fabian Dirks
|
||||
* Copyright (C) 2017-2023 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -863,13 +863,13 @@ obs_properties_t* blur_factory::get_properties2(blur_instance* data)
|
|||
OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_string(p, "", "");
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
obs_property_list_add_string(p, std::string(name + " (Source)").c_str(), name.c_str());
|
||||
return false;
|
||||
},
|
||||
obs::source_tracker::filter_video_sources);
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
obs_property_list_add_string(p, std::string(name + " (Scene)").c_str(), name.c_str());
|
||||
return false;
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2019 Michael Fabian Dirks
|
||||
* Copyright (C) 2019-2023 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -754,7 +754,7 @@ obs_properties_t* dynamic_mask_factory::get_properties2(dynamic_mask_instance* d
|
|||
OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_string(p, "", "");
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
std::stringstream sstr;
|
||||
sstr << name << " (" << D_TRANSLATE(S_SOURCETYPE_SOURCE) << ")";
|
||||
obs_property_list_add_string(p, sstr.str().c_str(), name.c_str());
|
||||
|
@ -762,7 +762,7 @@ obs_properties_t* dynamic_mask_factory::get_properties2(dynamic_mask_instance* d
|
|||
},
|
||||
obs::source_tracker::filter_video_sources);
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
std::stringstream sstr;
|
||||
sstr << name << " (" << D_TRANSLATE(S_SOURCETYPE_SCENE) << ")";
|
||||
obs_property_list_add_string(p, sstr.str().c_str(), name.c_str());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Modern effects for a modern Streamer
|
||||
// Copyright (C) 2019 Michael Fabian Dirks
|
||||
// Copyright (C) 2019-2023 Michael Fabian Dirks
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -215,7 +215,7 @@ void streamfx::gfx::shader::texture_parameter::properties(obs_properties_t* prop
|
|||
OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_string(p, "", "");
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
std::stringstream sstr;
|
||||
sstr << name << " (" << D_TRANSLATE(S_SOURCETYPE_SOURCE) << ")";
|
||||
obs_property_list_add_string(p, sstr.str().c_str(), name.c_str());
|
||||
|
@ -223,7 +223,7 @@ void streamfx::gfx::shader::texture_parameter::properties(obs_properties_t* prop
|
|||
},
|
||||
obs::source_tracker::filter_video_sources);
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
std::stringstream sstr;
|
||||
sstr << name << " (" << D_TRANSLATE(S_SOURCETYPE_SCENE) << ")";
|
||||
obs_property_list_add_string(p, sstr.str().c_str(), name.c_str());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2017-2018 Michael Fabian Dirks
|
||||
* Copyright (C) 2017-2023 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -40,6 +40,158 @@
|
|||
#define D_LOG_DEBUG(...) P_LOG_DEBUG(ST_PREFIX __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
streamfx::obs::source_tracker::source_tracker() : _sources(), _mutex()
|
||||
{
|
||||
auto osi = obs_get_signal_handler();
|
||||
if (osi) {
|
||||
signal_handler_connect(osi, "source_create", &source_create_handler, this);
|
||||
signal_handler_connect(osi, "source_destroy", &source_destroy_handler, this);
|
||||
signal_handler_connect(osi, "source_rename", &source_rename_handler, this);
|
||||
} else {
|
||||
D_LOG_WARNING("No global signal handler was present at initialization.", nullptr)
|
||||
}
|
||||
|
||||
// Enumerate all current sources and filters.
|
||||
obs_enum_all_sources(
|
||||
[](void* param, obs_source_t* source) {
|
||||
auto* self = reinterpret_cast<::streamfx::obs::source_tracker*>(param);
|
||||
self->insert_source(source);
|
||||
return true;
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
streamfx::obs::source_tracker::~source_tracker()
|
||||
{
|
||||
auto osi = obs_get_signal_handler();
|
||||
if (osi) {
|
||||
signal_handler_disconnect(osi, "source_create", &source_create_handler, this);
|
||||
signal_handler_disconnect(osi, "source_destroy", &source_destroy_handler, this);
|
||||
signal_handler_disconnect(osi, "source_rename", &source_rename_handler, this);
|
||||
}
|
||||
|
||||
this->_sources.clear();
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::enumerate(enumerate_cb_t ecb, filter_cb_t fcb)
|
||||
{
|
||||
// Need func-local copy, otherwise we risk corruption if a new source is created or destroyed.
|
||||
decltype(_sources) _clone;
|
||||
{
|
||||
std::lock_guard<decltype(_mutex)> lock(_mutex);
|
||||
_clone = _sources;
|
||||
}
|
||||
|
||||
for (auto kv : _clone) {
|
||||
auto wsource = kv.second;
|
||||
try {
|
||||
auto source = wsource.lock();
|
||||
|
||||
if (fcb) {
|
||||
if (fcb(kv.first, source)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ecb) {
|
||||
if (ecb(kv.first, source)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::insert_source(obs_source_t* source)
|
||||
{
|
||||
const char* name = obs_source_get_name(source);
|
||||
|
||||
// Don't track unnamed sources.
|
||||
if (!name || (strnlen(name, 1) == 0)) {
|
||||
D_LOG_DEBUG("Unnamed source '0x%08zX' left untracked.", source);
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert the newly tracked source into the map.
|
||||
std::lock_guard<decltype(_mutex)> lock(_mutex);
|
||||
_sources.emplace(std::string{name}, ::streamfx::obs::weak_source{source});
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::remove_source(obs_source_t* source)
|
||||
{
|
||||
std::lock_guard<decltype(_mutex)> lock(_mutex);
|
||||
const char* name = obs_source_get_name(source);
|
||||
|
||||
// Try and find the source by name.
|
||||
if (name) {
|
||||
if (auto kv = _sources.find(std::string{name}); kv != _sources.end()) {
|
||||
_sources.erase(kv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try and find the source by pointer.
|
||||
for (auto kv = _sources.begin(); kv != _sources.end(); kv++) {
|
||||
if (kv->second == source) {
|
||||
_sources.erase(kv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're still here, there's something wrong.
|
||||
if (name) {
|
||||
D_LOG_ERROR("Attempt to remove untracked source '0x%08zX' with name %s failed.", source, name);
|
||||
throw std::runtime_error("Failed to find given source.");
|
||||
}
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::rename_source(std::string_view old_name, std::string_view new_name,
|
||||
obs_source_t* source)
|
||||
{
|
||||
if (old_name == new_name) {
|
||||
throw std::runtime_error("New and old name are identical.");
|
||||
}
|
||||
|
||||
std::lock_guard<decltype(_mutex)> lock(_mutex);
|
||||
|
||||
// Remove the previously tracked entry.
|
||||
if (auto kv = _sources.find(std::string{old_name}); kv != _sources.end()) {
|
||||
_sources.erase(kv);
|
||||
}
|
||||
|
||||
// And then add the new entry.
|
||||
_sources.emplace(std::string{new_name}, ::streamfx::obs::weak_source{source});
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_sources(std::string, ::streamfx::obs::source source)
|
||||
{
|
||||
return (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_audio_sources(std::string, ::streamfx::obs::source source)
|
||||
{
|
||||
uint32_t flags = obs_source_get_output_flags(source);
|
||||
return !(flags & OBS_SOURCE_AUDIO) || (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_video_sources(std::string, ::streamfx::obs::source source)
|
||||
{
|
||||
uint32_t flags = obs_source_get_output_flags(source);
|
||||
return !(flags & OBS_SOURCE_VIDEO) || (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_transitions(std::string, ::streamfx::obs::source source)
|
||||
{
|
||||
return (obs_source_get_type(source) != OBS_SOURCE_TYPE_TRANSITION);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_scenes(std::string, ::streamfx::obs::source source)
|
||||
{
|
||||
return (obs_source_get_type(source) != OBS_SOURCE_TYPE_SCENE);
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::source_create_handler(void* ptr, calldata_t* data) noexcept
|
||||
{
|
||||
auto* self = reinterpret_cast<streamfx::obs::source_tracker*>(ptr);
|
||||
|
@ -66,6 +218,7 @@ void streamfx::obs::source_tracker::source_destroy_handler(void* ptr, calldata_t
|
|||
throw std::runtime_error("Missing 'source' parameter.");
|
||||
}
|
||||
|
||||
self->remove_source(source);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Event 'source_destroy' caused exception: %s", ex.what());
|
||||
} catch (...) {
|
||||
|
@ -98,161 +251,6 @@ void streamfx::obs::source_tracker::source_rename_handler(void* ptr, calldata_t*
|
|||
}
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::insert_source(obs_source_t* source)
|
||||
{
|
||||
const auto* name = obs_source_get_name(source);
|
||||
if (!name) { // Do not track unnamed sources.
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<obs_weak_source_t> weak{obs_source_get_weak_source(source), streamfx::obs::obs_weak_source_deleter};
|
||||
if (!weak) { // This source has already been deleted, do not track.
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_sources.insert({
|
||||
std::string(name),
|
||||
weak,
|
||||
});
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::remove_source(obs_source_t* source)
|
||||
{
|
||||
const char* name = obs_source_get_name(source);
|
||||
|
||||
// Lock read & write access to the map.
|
||||
std::unique_lock<std::mutex> ul(_mutex);
|
||||
|
||||
// Try and remove the source by name.
|
||||
if (name != nullptr) {
|
||||
auto found = _sources.find(std::string(name));
|
||||
if (found != _sources.end()) {
|
||||
_sources.erase(found);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If that didn't work, try and remove it by handle.
|
||||
for (auto iter = _sources.begin(); iter != _sources.end(); iter++) {
|
||||
if (obs_weak_source_get_source(iter->second.get()) == source) {
|
||||
_sources.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If that all failed, and the source is named, throw and report an error.
|
||||
if (name) {
|
||||
D_LOG_WARNING("Source '%s' was not tracked.", name);
|
||||
throw std::runtime_error("Failed to find given source.");
|
||||
}
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::rename_source(std::string_view old_name, std::string_view new_name,
|
||||
obs_source_t* source)
|
||||
{
|
||||
if (old_name == new_name) {
|
||||
throw std::runtime_error("New and old name are identical.");
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> ul(_mutex);
|
||||
auto found = _sources.find(std::string(old_name));
|
||||
if (found == _sources.end()) {
|
||||
insert_source(source);
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert at new key, remove old pair.
|
||||
_sources.insert({new_name.data(), found->second});
|
||||
_sources.erase(found);
|
||||
}
|
||||
|
||||
streamfx::obs::source_tracker::source_tracker() : _sources(), _mutex()
|
||||
{
|
||||
auto osi = obs_get_signal_handler();
|
||||
signal_handler_connect(osi, "source_create", &source_create_handler, this);
|
||||
signal_handler_connect(osi, "source_destroy", &source_destroy_handler, this);
|
||||
signal_handler_connect(osi, "source_rename", &source_rename_handler, this);
|
||||
|
||||
// Enumerate all current sources and filters.
|
||||
obs_enum_all_sources(
|
||||
[](void* param, obs_source_t* source) {
|
||||
auto* self = reinterpret_cast<::streamfx::obs::source_tracker*>(param);
|
||||
self->insert_source(source);
|
||||
return true;
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
streamfx::obs::source_tracker::~source_tracker()
|
||||
{
|
||||
auto osi = obs_get_signal_handler();
|
||||
if (osi) {
|
||||
signal_handler_disconnect(osi, "source_create", &source_create_handler, this);
|
||||
signal_handler_disconnect(osi, "source_destroy", &source_destroy_handler, this);
|
||||
signal_handler_disconnect(osi, "source_rename", &source_rename_handler, this);
|
||||
}
|
||||
|
||||
this->_sources.clear();
|
||||
}
|
||||
|
||||
void streamfx::obs::source_tracker::enumerate(enumerate_cb_t ecb, filter_cb_t fcb)
|
||||
{
|
||||
// Need func-local copy, otherwise we risk corruption if a new source is created or destroyed.
|
||||
decltype(_sources) _clone;
|
||||
{
|
||||
std::unique_lock<std::mutex> ul(_mutex);
|
||||
_clone = _sources;
|
||||
}
|
||||
|
||||
for (auto kv : _clone) {
|
||||
auto source = std::shared_ptr<obs_source_t>(obs_weak_source_get_source(kv.second.get()),
|
||||
streamfx::obs::obs_source_deleter);
|
||||
if (!source) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fcb) {
|
||||
if (fcb(kv.first, source.get())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ecb) {
|
||||
if (ecb(kv.first, source.get())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_sources(std::string, obs_source_t* source)
|
||||
{
|
||||
return (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_audio_sources(std::string, obs_source_t* source)
|
||||
{
|
||||
uint32_t flags = obs_source_get_output_flags(source);
|
||||
return !(flags & OBS_SOURCE_AUDIO) || (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_video_sources(std::string, obs_source_t* source)
|
||||
{
|
||||
uint32_t flags = obs_source_get_output_flags(source);
|
||||
return !(flags & OBS_SOURCE_VIDEO) || (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_transitions(std::string, obs_source_t* source)
|
||||
{
|
||||
return (obs_source_get_type(source) != OBS_SOURCE_TYPE_TRANSITION);
|
||||
}
|
||||
|
||||
bool streamfx::obs::source_tracker::filter_scenes(std::string, obs_source_t* source)
|
||||
{
|
||||
return (obs_source_get_type(source) != OBS_SOURCE_TYPE_SCENE);
|
||||
}
|
||||
|
||||
std::shared_ptr<streamfx::obs::source_tracker> streamfx::obs::source_tracker::get()
|
||||
{
|
||||
static std::mutex inst_mtx;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2017-2018 Michael Fabian Dirks
|
||||
* Copyright (C) 2017-2023 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,6 +19,7 @@
|
|||
|
||||
#pragma once
|
||||
#include "common.hpp"
|
||||
#include "obs/obs-weak-source.hpp"
|
||||
|
||||
#include "warning-disable.hpp"
|
||||
#include <functional>
|
||||
|
@ -28,17 +29,8 @@
|
|||
|
||||
namespace streamfx::obs {
|
||||
class source_tracker {
|
||||
std::map<std::string, std::shared_ptr<obs_weak_source_t>> _sources;
|
||||
std::mutex _mutex;
|
||||
|
||||
static void source_create_handler(void* ptr, calldata_t* data) noexcept;
|
||||
static void source_destroy_handler(void* ptr, calldata_t* data) noexcept;
|
||||
static void source_rename_handler(void* ptr, calldata_t* data) noexcept;
|
||||
|
||||
protected:
|
||||
void insert_source(obs_source_t* source);
|
||||
void remove_source(obs_source_t* source);
|
||||
void rename_source(std::string_view old_name, std::string_view new_name, obs_source_t* source);
|
||||
std::map<std::string, ::streamfx::obs::weak_source> _sources;
|
||||
std::mutex _mutex;
|
||||
|
||||
public:
|
||||
// Callback function for enumerating sources.
|
||||
|
@ -46,14 +38,14 @@ namespace streamfx::obs {
|
|||
// @param std::string Name of the Source
|
||||
// @param obs_source_t* Source
|
||||
// @return true to abort enumeration, false to keep going.
|
||||
typedef std::function<bool(std::string, obs_source_t*)> enumerate_cb_t;
|
||||
typedef std::function<bool(std::string, ::streamfx::obs::source)> enumerate_cb_t;
|
||||
|
||||
// Filter function for enumerating sources.
|
||||
//
|
||||
// @param std::string Name of the Source
|
||||
// @param obs_source_t* Source
|
||||
// @return true to skip, false to pass along.
|
||||
typedef std::function<bool(std::string, obs_source_t*)> filter_cb_t;
|
||||
typedef std::function<bool(std::string, ::streamfx::obs::source)> filter_cb_t;
|
||||
|
||||
protected:
|
||||
source_tracker();
|
||||
|
@ -67,12 +59,22 @@ namespace streamfx::obs {
|
|||
// @param filter_cb Filter function to narrow down results.
|
||||
void enumerate(enumerate_cb_t enumerate_cb, filter_cb_t filter_cb = nullptr);
|
||||
|
||||
protected:
|
||||
void insert_source(obs_source_t* source);
|
||||
void remove_source(obs_source_t* source);
|
||||
void rename_source(std::string_view old_name, std::string_view new_name, obs_source_t* source);
|
||||
|
||||
public:
|
||||
static bool filter_sources(std::string name, obs_source_t* source);
|
||||
static bool filter_audio_sources(std::string name, obs_source_t* source);
|
||||
static bool filter_video_sources(std::string name, obs_source_t* source);
|
||||
static bool filter_transitions(std::string name, obs_source_t* source);
|
||||
static bool filter_scenes(std::string name, obs_source_t* source);
|
||||
static bool filter_sources(std::string name, ::streamfx::obs::source source);
|
||||
static bool filter_audio_sources(std::string name, ::streamfx::obs::source source);
|
||||
static bool filter_video_sources(std::string name, ::streamfx::obs::source source);
|
||||
static bool filter_transitions(std::string name, ::streamfx::obs::source source);
|
||||
static bool filter_scenes(std::string name, ::streamfx::obs::source source);
|
||||
|
||||
private:
|
||||
static void source_create_handler(void* ptr, calldata_t* data) noexcept;
|
||||
static void source_destroy_handler(void* ptr, calldata_t* data) noexcept;
|
||||
static void source_rename_handler(void* ptr, calldata_t* data) noexcept;
|
||||
|
||||
public: // Singleton
|
||||
static std::shared_ptr<streamfx::obs::source_tracker> get();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Modern effects for a modern Streamer
|
||||
* Copyright (C) 2017 Michael Fabian Dirks
|
||||
* Copyright (C) 2017-2023 Michael Fabian Dirks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -348,7 +348,7 @@ obs_properties_t* mirror_factory::get_properties2(mirror_instance* data)
|
|||
|
||||
obs_property_list_add_string(p, "", "");
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
std::stringstream sstr;
|
||||
sstr << name << " (" << D_TRANSLATE(S_SOURCETYPE_SOURCE) << ")";
|
||||
obs_property_list_add_string(p, sstr.str().c_str(), name.c_str());
|
||||
|
@ -356,7 +356,7 @@ obs_properties_t* mirror_factory::get_properties2(mirror_instance* data)
|
|||
},
|
||||
obs::source_tracker::filter_sources);
|
||||
obs::source_tracker::get()->enumerate(
|
||||
[&p](std::string name, obs_source_t*) {
|
||||
[&p](std::string name, ::streamfx::obs::source) {
|
||||
std::stringstream sstr;
|
||||
sstr << name << " (" << D_TRANSLATE(S_SOURCETYPE_SCENE) << ")";
|
||||
obs_property_list_add_string(p, sstr.str().c_str(), name.c_str());
|
||||
|
|
Loading…
Reference in New Issue