Update C++ files with braces

This commit is contained in:
Warchamp7
2026-06-09 13:41:19 -04:00
committed by Ryan Foster
parent 32bf5100fb
commit 30b63c6849
259 changed files with 7725 additions and 4086 deletions
+141 -73
View File
@@ -143,9 +143,10 @@ UncleanLaunchAction handleUncleanShutdown(bool enableCrashUpload)
QAccessibleInterface *alignmentSelectorFactory(const QString &classname, QObject *object) QAccessibleInterface *alignmentSelectorFactory(const QString &classname, QObject *object)
{ {
if (classname == QLatin1String("AlignmentSelector")) { if (classname == QLatin1String("AlignmentSelector")) {
if (auto *w = qobject_cast<AlignmentSelector *>(object)) if (auto *w = qobject_cast<AlignmentSelector *>(object)) {
return new AccessibleAlignmentSelector(w); return new AccessibleAlignmentSelector(w);
} }
}
return nullptr; return nullptr;
} }
} // namespace } // namespace
@@ -154,8 +155,9 @@ QObject *CreateShortcutFilter()
{ {
return new OBSEventFilter([](QObject *obj, QEvent *event) { return new OBSEventFilter([](QObject *obj, QEvent *event) {
auto mouse_event = [](QMouseEvent &event) { auto mouse_event = [](QMouseEvent &event) {
if (!App()->HotkeysEnabledInFocus() && event.button() != Qt::LeftButton) if (!App()->HotkeysEnabledInFocus() && event.button() != Qt::LeftButton) {
return true; return true;
}
obs_key_combination_t hotkey = {0, OBS_KEY_NONE}; obs_key_combination_t hotkey = {0, OBS_KEY_NONE};
bool pressed = event.type() == QEvent::MouseButtonPress; bool pressed = event.type() == QEvent::MouseButtonPress;
@@ -407,37 +409,49 @@ static bool MakeUserDirs()
{ {
char path[512]; char path[512];
if (GetAppConfigPath(path, sizeof(path), "obs-studio/basic") <= 0) if (GetAppConfigPath(path, sizeof(path), "obs-studio/basic") <= 0) {
return false; return false;
if (!do_mkdir(path)) }
if (!do_mkdir(path)) {
return false; return false;
}
if (GetAppConfigPath(path, sizeof(path), "obs-studio/logs") <= 0) if (GetAppConfigPath(path, sizeof(path), "obs-studio/logs") <= 0) {
return false; return false;
if (!do_mkdir(path)) }
if (!do_mkdir(path)) {
return false; return false;
}
if (GetAppConfigPath(path, sizeof(path), "obs-studio/profiler_data") <= 0) if (GetAppConfigPath(path, sizeof(path), "obs-studio/profiler_data") <= 0) {
return false; return false;
if (!do_mkdir(path)) }
if (!do_mkdir(path)) {
return false; return false;
}
#ifdef _WIN32 #ifdef _WIN32
if (GetAppConfigPath(path, sizeof(path), "obs-studio/crashes") <= 0) if (GetAppConfigPath(path, sizeof(path), "obs-studio/crashes") <= 0) {
return false; return false;
if (!do_mkdir(path)) }
if (!do_mkdir(path)) {
return false; return false;
}
#endif #endif
if (GetAppConfigPath(path, sizeof(path), "obs-studio/updates") <= 0) if (GetAppConfigPath(path, sizeof(path), "obs-studio/updates") <= 0) {
return false; return false;
if (!do_mkdir(path)) }
if (!do_mkdir(path)) {
return false; return false;
}
if (GetAppConfigPath(path, sizeof(path), "obs-studio/plugin_config") <= 0) if (GetAppConfigPath(path, sizeof(path), "obs-studio/plugin_config") <= 0) {
return false; return false;
if (!do_mkdir(path)) }
if (!do_mkdir(path)) {
return false; return false;
}
return true; return true;
} }
@@ -490,8 +504,9 @@ static bool MakeUserProfileDirs()
bool OBSApp::UpdatePre22MultiviewLayout(const char *layout) bool OBSApp::UpdatePre22MultiviewLayout(const char *layout)
{ {
if (!layout) if (!layout) {
return false; return false;
}
if (astrcmpi(layout, "horizontaltop") == 0) { if (astrcmpi(layout, "horizontaltop") == 0) {
config_set_int(userConfig, "BasicWindow", "MultiviewLayout", config_set_int(userConfig, "BasicWindow", "MultiviewLayout",
@@ -703,14 +718,16 @@ bool OBSApp::InitLocale()
const char *lang = config_get_string(userConfig, "General", "Language"); const char *lang = config_get_string(userConfig, "General", "Language");
bool userLocale = config_has_user_value(userConfig, "General", "Language"); bool userLocale = config_has_user_value(userConfig, "General", "Language");
if (!userLocale || !lang || lang[0] == '\0') if (!userLocale || !lang || lang[0] == '\0') {
lang = DEFAULT_LANG; lang = DEFAULT_LANG;
}
locale = lang; locale = lang;
// set basic default application locale // set basic default application locale
if (!locale.empty()) if (!locale.empty()) {
QLocale::setDefault(QLocale(QString::fromStdString(locale).replace('-', '_'))); QLocale::setDefault(QLocale(QString::fromStdString(locale).replace('-', '_')));
}
string englishPath; string englishPath;
if (!GetDataFilePath("locale/" DEFAULT_LANG ".ini", englishPath)) { if (!GetDataFilePath("locale/" DEFAULT_LANG ".ini", englishPath)) {
@@ -726,30 +743,35 @@ bool OBSApp::InitLocale()
bool defaultLang = astrcmpi(lang, DEFAULT_LANG) == 0; bool defaultLang = astrcmpi(lang, DEFAULT_LANG) == 0;
if (userLocale && defaultLang) if (userLocale && defaultLang) {
return true; return true;
}
if (!userLocale && defaultLang) { if (!userLocale && defaultLang) {
for (auto &locale_ : GetPreferredLocales()) { for (auto &locale_ : GetPreferredLocales()) {
if (locale_ == lang) if (locale_ == lang) {
return true; return true;
}
stringstream file; stringstream file;
file << "locale/" << locale_ << ".ini"; file << "locale/" << locale_ << ".ini";
string path; string path;
if (!GetDataFilePath(file.str().c_str(), path)) if (!GetDataFilePath(file.str().c_str(), path)) {
continue; continue;
}
if (!text_lookup_add(textLookup, path.c_str())) if (!text_lookup_add(textLookup, path.c_str())) {
continue; continue;
}
blog(LOG_INFO, "Using preferred locale '%s'", locale_.c_str()); blog(LOG_INFO, "Using preferred locale '%s'", locale_.c_str());
locale = locale_; locale = locale_;
// set application default locale to the new chosen one // set application default locale to the new chosen one
if (!locale.empty()) if (!locale.empty()) {
QLocale::setDefault(QLocale(QString::fromStdString(locale).replace('-', '_'))); QLocale::setDefault(QLocale(QString::fromStdString(locale).replace('-', '_')));
}
return true; return true;
} }
@@ -762,8 +784,9 @@ bool OBSApp::InitLocale()
string path; string path;
if (GetDataFilePath(file.str().c_str(), path)) { if (GetDataFilePath(file.str().c_str(), path)) {
if (!text_lookup_add(textLookup, path.c_str())) if (!text_lookup_add(textLookup, path.c_str())) {
blog(LOG_ERROR, "Failed to add locale file '%s'", path.c_str()); blog(LOG_ERROR, "Failed to add locale file '%s'", path.c_str());
}
} else { } else {
blog(LOG_ERROR, "Could not find locale file '%s'", file.str().c_str()); blog(LOG_ERROR, "Could not find locale file '%s'", file.str().c_str());
} }
@@ -786,11 +809,13 @@ void ParseBranchesJson(const std::string &jsonString, vector<UpdateBranch> &out,
for (const JsonBranch &json_branch : branches) { for (const JsonBranch &json_branch : branches) {
#ifdef _WIN32 #ifdef _WIN32
if (!json_branch.windows) if (!json_branch.windows) {
continue; continue;
}
#elif defined(__APPLE__) #elif defined(__APPLE__)
if (!json_branch.macos) if (!json_branch.macos) {
continue; continue;
}
#endif #endif
UpdateBranch branch = { UpdateBranch branch = {
@@ -824,8 +849,9 @@ bool LoadBranchesFile(vector<UpdateBranch> &out)
} }
ParseBranchesJson(branchesText, out, error); ParseBranchesJson(branchesText, out, error);
if (error.empty()) if (error.empty()) {
return !out.empty(); return !out.empty();
}
fail: fail:
blog(LOG_WARNING, "Loading branches from file failed: %s", error.c_str()); blog(LOG_WARNING, "Loading branches from file failed: %s", error.c_str());
@@ -846,8 +872,9 @@ void OBSApp::SetBranchData(const string &data)
return; return;
} }
if (!result.empty()) if (!result.empty()) {
updateBranches = result; updateBranches = result;
}
branches_loaded = true; branches_loaded = true;
#else #else
@@ -864,16 +891,18 @@ std::vector<UpdateBranch> OBSApp::GetBranches()
#if defined(_WIN32) || defined(ENABLE_SPARKLE_UPDATER) #if defined(_WIN32) || defined(ENABLE_SPARKLE_UPDATER)
if (!branches_loaded) { if (!branches_loaded) {
vector<UpdateBranch> result; vector<UpdateBranch> result;
if (LoadBranchesFile(result)) if (LoadBranchesFile(result)) {
updateBranches = result; updateBranches = result;
}
branches_loaded = true; branches_loaded = true;
} }
#endif #endif
/* Copy additional branches to result (if any) */ /* Copy additional branches to result (if any) */
if (!updateBranches.empty()) if (!updateBranches.empty()) {
out.insert(out.end(), updateBranches.begin(), updateBranches.end()); out.insert(out.end(), updateBranches.begin(), updateBranches.end());
}
return out; return out;
} }
@@ -887,8 +916,9 @@ OBSApp::OBSApp(int &argc, char **argv, profiler_name_store_t *store)
/* fix float handling */ /* fix float handling */
#if defined(Q_OS_UNIX) #if defined(Q_OS_UNIX)
if (!setlocale(LC_NUMERIC, "C")) if (!setlocale(LC_NUMERIC, "C")) {
blog(LOG_WARNING, "Failed to set LC_NUMERIC to C locale"); blog(LOG_WARNING, "Failed to set LC_NUMERIC to C locale");
}
#endif #endif
#ifndef _WIN32 #ifndef _WIN32
@@ -1050,14 +1080,18 @@ void OBSApp::AppInit()
QAccessible::installFactory(alignmentSelectorFactory); QAccessible::installFactory(alignmentSelectorFactory);
if (!MakeUserDirs()) if (!MakeUserDirs()) {
throw "Failed to create required user directories"; throw "Failed to create required user directories";
if (!InitGlobalConfig()) }
if (!InitGlobalConfig()) {
throw "Failed to initialize global config"; throw "Failed to initialize global config";
if (!InitLocale()) }
if (!InitLocale()) {
throw "Failed to load locale"; throw "Failed to load locale";
if (!InitTheme()) }
if (!InitTheme()) {
throw "Failed to load theme"; throw "Failed to load theme";
}
config_set_default_string(userConfig, "Basic", "Profile", Str("Untitled")); config_set_default_string(userConfig, "Basic", "Profile", Str("Untitled"));
config_set_default_string(userConfig, "Basic", "ProfileDir", Str("Untitled")); config_set_default_string(userConfig, "Basic", "ProfileDir", Str("Untitled"));
@@ -1081,13 +1115,15 @@ void OBSApp::AppInit()
#ifdef _WIN32 #ifdef _WIN32
bool disableAudioDucking = config_get_bool(appConfig, "Audio", "DisableAudioDucking"); bool disableAudioDucking = config_get_bool(appConfig, "Audio", "DisableAudioDucking");
if (disableAudioDucking) if (disableAudioDucking) {
DisableAudioDucking(true); DisableAudioDucking(true);
}
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
if (config_get_bool(appConfig, "Video", "DisableOSXVSync")) if (config_get_bool(appConfig, "Video", "DisableOSXVSync")) {
EnableOSXVSync(false); EnableOSXVSync(false);
}
#endif #endif
UpdateHotkeyFocusSetting(false); UpdateHotkeyFocusSetting(false);
@@ -1095,9 +1131,10 @@ void OBSApp::AppInit()
move_basic_to_profiles(); move_basic_to_profiles();
move_basic_to_scene_collections(); move_basic_to_scene_collections();
if (!MakeUserProfileDirs()) if (!MakeUserProfileDirs()) {
throw "Failed to create profile directories"; throw "Failed to create profile directories";
} }
}
void OBSApp::checkForUncleanShutdown() void OBSApp::checkForUncleanShutdown()
{ {
@@ -1134,8 +1171,9 @@ static bool StartupOBS(const char *locale, profiler_name_store_t *store)
{ {
char path[512]; char path[512];
if (GetAppConfigPath(path, sizeof(path), "obs-studio/plugin_config") <= 0) if (GetAppConfigPath(path, sizeof(path), "obs-studio/plugin_config") <= 0) {
return false; return false;
}
return obs_startup(locale, path, store); return obs_startup(locale, path, store);
} }
@@ -1158,9 +1196,10 @@ void OBSApp::UpdateHotkeyFocusSetting(bool resetState)
enableHotkeysOutOfFocus = false; enableHotkeysOutOfFocus = false;
} }
if (resetState) if (resetState) {
ResetHotkeyState(applicationState() == Qt::ApplicationActive); ResetHotkeyState(applicationState() == Qt::ApplicationActive);
} }
}
void OBSApp::DisableHotkeys() void OBSApp::DisableHotkeys()
{ {
@@ -1227,8 +1266,9 @@ bool OBSApp::OBSInit()
setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
#endif #endif
if (!StartupOBS(locale.c_str(), GetProfilerNameStore())) if (!StartupOBS(locale.c_str(), GetProfilerNameStore())) {
return false; return false;
}
libobs_initialized = true; libobs_initialized = true;
@@ -1296,10 +1336,11 @@ string OBSApp::GetVersionString(bool platform) const
if (platform) { if (platform) {
ver << " ("; ver << " (";
#ifdef _WIN32 #ifdef _WIN32
if (sizeof(void *) == 8) if (sizeof(void *) == 8) {
ver << "64-bit, "; ver << "64-bit, ";
else } else {
ver << "32-bit, "; ver << "32-bit, ";
}
ver << "windows)"; ver << "windows)";
#elif __APPLE__ #elif __APPLE__
@@ -1414,9 +1455,10 @@ OBS::LogFileState OBSApp::getLogFileState(OBS::LogFileType type) const
bool OBSApp::TranslateString(const char *lookupVal, const char **out) const bool OBSApp::TranslateString(const char *lookupVal, const char **out) const
{ {
for (obs_frontend_translate_ui_cb cb : translatorHooks) { for (obs_frontend_translate_ui_cb cb : translatorHooks) {
if (cb(lookupVal, out)) if (cb(lookupVal, out)) {
return true; return true;
} }
}
return text_lookup_getstr(App()->GetTextLookup(), lookupVal, out); return text_lookup_getstr(App()->GetTextLookup(), lookupVal, out);
} }
@@ -1438,29 +1480,34 @@ bool OBSApp::notify(QObject *receiver, QEvent *e)
QWindow *window; QWindow *window;
int windowType; int windowType;
if (!receiver->isWidgetType()) if (!receiver->isWidgetType()) {
goto skip; goto skip;
}
if (e->type() != QEvent::Show) if (e->type() != QEvent::Show) {
goto skip; goto skip;
}
w = qobject_cast<QWidget *>(receiver); w = qobject_cast<QWidget *>(receiver);
if (!w->isWindow()) if (!w->isWindow()) {
goto skip; goto skip;
}
window = w->windowHandle(); window = w->windowHandle();
if (!window) if (!window) {
goto skip; goto skip;
}
windowType = window->flags() & Qt::WindowType::WindowType_Mask; windowType = window->flags() & Qt::WindowType::WindowType_Mask;
if (windowType == Qt::WindowType::Dialog || windowType == Qt::WindowType::Window || if (windowType == Qt::WindowType::Dialog || windowType == Qt::WindowType::Window ||
windowType == Qt::WindowType::Tool) { windowType == Qt::WindowType::Tool) {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
if (main) if (main) {
main->SetDisplayAffinity(window); main->SetDisplayAffinity(window);
} }
}
skip: skip:
return QApplication::notify(receiver, e); return QApplication::notify(receiver, e);
@@ -1490,12 +1537,14 @@ static void FindBestFilename(string &strPath, bool noSpace)
{ {
int num = 2; int num = 2;
if (!os_file_exists(strPath.c_str())) if (!os_file_exists(strPath.c_str())) {
return; return;
}
const char *ext = strrchr(strPath.c_str(), '.'); const char *ext = strrchr(strPath.c_str(), '.');
if (!ext) if (!ext) {
return; return;
}
int extStart = int(ext - strPath.c_str()); int extStart = int(ext - strPath.c_str());
for (;;) { for (;;) {
@@ -1504,8 +1553,9 @@ static void FindBestFilename(string &strPath, bool noSpace)
numStr = noSpace ? "_" : " ("; numStr = noSpace ? "_" : " (";
numStr += to_string(num++); numStr += to_string(num++);
if (!noSpace) if (!noSpace) {
numStr += ")"; numStr += ")";
}
testPath.insert(extStart, numStr); testPath.insert(extStart, numStr);
@@ -1521,8 +1571,9 @@ static void ensure_directory_exists(string &path)
replace(path.begin(), path.end(), '\\', '/'); replace(path.begin(), path.end(), '\\', '/');
size_t last = path.rfind('/'); size_t last = path.rfind('/');
if (last == string::npos) if (last == string::npos) {
return; return;
}
string directory = path.substr(0, last); string directory = path.substr(0, last);
os_mkdirs(directory.c_str()); os_mkdirs(directory.c_str());
@@ -1549,26 +1600,30 @@ string GetFormatString(const char *format, const char *prefix, const char *suffi
if (prefix && *prefix) { if (prefix && *prefix) {
string str_prefix = prefix; string str_prefix = prefix;
if (str_prefix.back() != ' ') if (str_prefix.back() != ' ') {
str_prefix += " "; str_prefix += " ";
}
size_t insert_pos = 0; size_t insert_pos = 0;
size_t tmp; size_t tmp;
tmp = f.find_last_of('/'); tmp = f.find_last_of('/');
if (tmp != string::npos && tmp > insert_pos) if (tmp != string::npos && tmp > insert_pos) {
insert_pos = tmp + 1; insert_pos = tmp + 1;
}
tmp = f.find_last_of('\\'); tmp = f.find_last_of('\\');
if (tmp != string::npos && tmp > insert_pos) if (tmp != string::npos && tmp > insert_pos) {
insert_pos = tmp + 1; insert_pos = tmp + 1;
}
f.insert(insert_pos, str_prefix); f.insert(insert_pos, str_prefix);
} }
if (suffix && *suffix) { if (suffix && *suffix) {
if (*suffix != ' ') if (*suffix != ' ') {
f += " "; f += " ";
}
f += suffix; f += suffix;
} }
@@ -1580,14 +1635,15 @@ string GetFormatString(const char *format, const char *prefix, const char *suffi
string GetFormatExt(const char *container) string GetFormatExt(const char *container)
{ {
string ext = container; string ext = container;
if (ext == "fragmented_mp4" || ext == "hybrid_mp4") if (ext == "fragmented_mp4" || ext == "hybrid_mp4") {
ext = "mp4"; ext = "mp4";
else if (ext == "fragmented_mov" || ext == "hybrid_mov") } else if (ext == "fragmented_mov" || ext == "hybrid_mov") {
ext = "mov"; ext = "mov";
else if (ext == "hls") } else if (ext == "hls") {
ext = "m3u8"; ext = "m3u8";
else if (ext == "mpegts") } else if (ext == "mpegts") {
ext = "ts"; ext = "ts";
}
return ext; return ext;
} }
@@ -1599,10 +1655,11 @@ string GetOutputFilename(const char *path, const char *container, bool noSpace,
os_dir_t *dir = path && path[0] ? os_opendir(path) : nullptr; os_dir_t *dir = path && path[0] ? os_opendir(path) : nullptr;
if (!dir) { if (!dir) {
if (main->isVisible()) if (main->isVisible()) {
OBSMessageBox::warning(main, QTStr("Output.BadPath.Title"), QTStr("Output.BadPath.Text")); OBSMessageBox::warning(main, QTStr("Output.BadPath.Title"), QTStr("Output.BadPath.Text"));
else } else {
main->SysTrayNotify(QTStr("Output.BadPath.Text"), QSystemTrayIcon::Warning); main->SysTrayNotify(QTStr("Output.BadPath.Text"), QSystemTrayIcon::Warning);
}
return ""; return "";
} }
@@ -1612,14 +1669,16 @@ string GetOutputFilename(const char *path, const char *container, bool noSpace,
strPath += path; strPath += path;
char lastChar = strPath.back(); char lastChar = strPath.back();
if (lastChar != '/' && lastChar != '\\') if (lastChar != '/' && lastChar != '\\') {
strPath += "/"; strPath += "/";
}
string ext = GetFormatExt(container); string ext = GetFormatExt(container);
strPath += GenerateSpecifiedFilename(ext.c_str(), noSpace, format); strPath += GenerateSpecifiedFilename(ext.c_str(), noSpace, format);
ensure_directory_exists(strPath); ensure_directory_exists(strPath);
if (!overwrite) if (!overwrite) {
FindBestFilename(strPath, noSpace); FindBestFilename(strPath, noSpace);
}
return strPath; return strPath;
} }
@@ -1627,12 +1686,14 @@ string GetOutputFilename(const char *path, const char *container, bool noSpace,
vector<pair<string, string>> GetLocaleNames() vector<pair<string, string>> GetLocaleNames()
{ {
string path; string path;
if (!GetDataFilePath("locale.ini", path)) if (!GetDataFilePath("locale.ini", path)) {
throw "Could not find locale.ini path"; throw "Could not find locale.ini path";
}
ConfigFile ini; ConfigFile ini;
if (ini.Open(path.c_str(), CONFIG_OPEN_EXISTING) != 0) if (ini.Open(path.c_str(), CONFIG_OPEN_EXISTING) != 0) {
throw "Could not open locale.ini"; throw "Could not open locale.ini";
}
size_t sections = config_num_sections(ini); size_t sections = config_num_sections(ini);
@@ -1713,8 +1774,9 @@ bool GetFileSafeName(const char *name, std::string &file)
size_t len = os_utf8_to_wcs(name, base_len, nullptr, 0); size_t len = os_utf8_to_wcs(name, base_len, nullptr, 0);
std::wstring wfile; std::wstring wfile;
if (!len) if (!len) {
return false; return false;
}
wfile.resize(len); wfile.resize(len);
os_utf8_to_wcs(name, base_len, &wfile[0], len + 1); os_utf8_to_wcs(name, base_len, &wfile[0], len + 1);
@@ -1729,12 +1791,14 @@ bool GetFileSafeName(const char *name, std::string &file)
} }
} }
if (wfile.size() == 0) if (wfile.size() == 0) {
wfile = L"characters_only"; wfile = L"characters_only";
}
len = os_wcs_to_utf8(wfile.c_str(), wfile.size(), nullptr, 0); len = os_wcs_to_utf8(wfile.c_str(), wfile.size(), nullptr, 0);
if (!len) if (!len) {
return false; return false;
}
file.resize(len); file.resize(len);
os_wcs_to_utf8(wfile.c_str(), wfile.size(), &file[0], len + 1); os_wcs_to_utf8(wfile.c_str(), wfile.size(), &file[0], len + 1);
@@ -1749,8 +1813,9 @@ bool GetClosestUnusedFileName(std::string &path, const char *extension)
path += extension; path += extension;
} }
if (!os_file_exists(path.c_str())) if (!os_file_exists(path.c_str())) {
return true; return true;
}
int index = 1; int index = 1;
@@ -1769,9 +1834,10 @@ bool GetClosestUnusedFileName(std::string &path, const char *extension)
bool WindowPositionValid(QRect rect) bool WindowPositionValid(QRect rect)
{ {
for (QScreen *screen : QGuiApplication::screens()) { for (QScreen *screen : QGuiApplication::screens()) {
if (screen->availableGeometry().intersects(rect)) if (screen->availableGeometry().intersects(rect)) {
return true; return true;
} }
}
return false; return false;
} }
@@ -1930,8 +1996,9 @@ void OBSApp::applicationShutdown() noexcept
{ {
#ifdef _WIN32 #ifdef _WIN32
bool disableAudioDucking = config_get_bool(appConfig, "Audio", "DisableAudioDucking"); bool disableAudioDucking = config_get_bool(appConfig, "Audio", "DisableAudioDucking");
if (disableAudioDucking) if (disableAudioDucking) {
DisableAudioDucking(false); DisableAudioDucking(false);
}
#else #else
auto disconnectSignal = [this](std::array<int, 2> &fileDescriptor, auto disconnectSignal = [this](std::array<int, 2> &fileDescriptor,
QPointer<QSocketNotifier> &notifier) -> void { QPointer<QSocketNotifier> &notifier) -> void {
@@ -1951,8 +2018,9 @@ void OBSApp::applicationShutdown() noexcept
#ifdef __APPLE__ #ifdef __APPLE__
bool vsyncDisabled = config_get_bool(appConfig, "Video", "DisableOSXVSync"); bool vsyncDisabled = config_get_bool(appConfig, "Video", "DisableOSXVSync");
bool resetVSync = config_get_bool(appConfig, "Video", "ResetOSXVSyncOnExit"); bool resetVSync = config_get_bool(appConfig, "Video", "ResetOSXVSyncOnExit");
if (vsyncDisabled && resetVSync) if (vsyncDisabled && resetVSync) {
EnableOSXVSync(true); EnableOSXVSync(true);
}
#endif #endif
os_inhibit_sleep_set_active(sleepInhibitor, false); os_inhibit_sleep_set_active(sleepInhibitor, false);
+10 -5
View File
@@ -205,21 +205,26 @@ public:
inline void IncrementSleepInhibition() inline void IncrementSleepInhibition()
{ {
if (!sleepInhibitor) if (!sleepInhibitor) {
return; return;
if (sleepInhibitRefs++ == 0) }
if (sleepInhibitRefs++ == 0) {
os_inhibit_sleep_set_active(sleepInhibitor, true); os_inhibit_sleep_set_active(sleepInhibitor, true);
} }
}
inline void DecrementSleepInhibition() inline void DecrementSleepInhibition()
{ {
if (!sleepInhibitor) if (!sleepInhibitor) {
return; return;
if (sleepInhibitRefs == 0) }
if (sleepInhibitRefs == 0) {
return; return;
if (--sleepInhibitRefs == 0) }
if (--sleepInhibitRefs == 0) {
os_inhibit_sleep_set_active(sleepInhibitor, false); os_inhibit_sleep_set_active(sleepInhibitor, false);
} }
}
inline void PushUITranslation(obs_frontend_translate_ui_cb cb) { translatorHooks.emplace_front(cb); } inline void PushUITranslation(obs_frontend_translate_ui_cb cb) { translatorHooks.emplace_front(cb); }
+158 -90
View File
@@ -46,16 +46,18 @@ struct CFParser {
static optional<OBSTheme> ParseThemeMeta(const QString &path) static optional<OBSTheme> ParseThemeMeta(const QString &path)
{ {
QFile themeFile(path); QFile themeFile(path);
if (!themeFile.open(QIODeviceBase::ReadOnly)) if (!themeFile.open(QIODeviceBase::ReadOnly)) {
return nullopt; return nullopt;
}
OBSTheme meta; OBSTheme meta;
const QByteArray data = themeFile.readAll(); const QByteArray data = themeFile.readAll();
CFParser cfp; CFParser cfp;
int ret; int ret;
if (!cf_parser_parse(cfp, data.constData(), QT_TO_UTF8(path))) if (!cf_parser_parse(cfp, data.constData(), QT_TO_UTF8(path))) {
return nullopt; return nullopt;
}
if (cf_token_is(cfp, "@") || cf_go_to_token(cfp, "@", nullptr)) { if (cf_token_is(cfp, "@") || cf_go_to_token(cfp, "@", nullptr)) {
while (cf_next_token(cfp)) { while (cf_next_token(cfp)) {
@@ -63,60 +65,71 @@ static optional<OBSTheme> ParseThemeMeta(const QString &path)
break; break;
} }
if (!cf_go_to_token(cfp, "@", nullptr)) if (!cf_go_to_token(cfp, "@", nullptr)) {
return nullopt;
}
}
if (!cf_token_is(cfp, "OBSThemeMeta")) {
return nullopt; return nullopt;
} }
if (!cf_token_is(cfp, "OBSThemeMeta")) if (!cf_next_token(cfp)) {
return nullopt; return nullopt;
}
if (!cf_next_token(cfp)) if (!cf_token_is(cfp, "{")) {
return nullopt;
if (!cf_token_is(cfp, "{"))
return nullopt; return nullopt;
}
for (;;) { for (;;) {
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return nullopt; return nullopt;
}
ret = cf_token_is_type(cfp, CFTOKEN_NAME, "name", nullptr); ret = cf_token_is_type(cfp, CFTOKEN_NAME, "name", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
break; break;
}
string name(cfp->cur_token->str.array, cfp->cur_token->str.len); string name(cfp->cur_token->str.array, cfp->cur_token->str.len);
ret = cf_next_token_should_be(cfp, ":", ";", nullptr); ret = cf_next_token_should_be(cfp, ":", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
continue; continue;
}
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return nullopt; return nullopt;
}
ret = cf_token_is_type(cfp, CFTOKEN_STRING, "value", ";"); ret = cf_token_is_type(cfp, CFTOKEN_STRING, "value", ";");
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
continue; continue;
}
BPtr str = cf_literal_to_str(cfp->cur_token->str.array, cfp->cur_token->str.len); BPtr str = cf_literal_to_str(cfp->cur_token->str.array, cfp->cur_token->str.len);
if (str) { if (str) {
if (name == "dark") if (name == "dark") {
meta.isDark = strcmp(str, "true") == 0; meta.isDark = strcmp(str, "true") == 0;
else if (name == "extends") } else if (name == "extends") {
meta.extends = str; meta.extends = str;
else if (name == "author") } else if (name == "author") {
meta.author = str; meta.author = str;
else if (name == "id") } else if (name == "id") {
meta.id = str; meta.id = str;
else if (name == "name") } else if (name == "name") {
meta.name = str; meta.name = str;
} }
}
if (!cf_go_to_token(cfp, ";", nullptr)) if (!cf_go_to_token(cfp, ";", nullptr)) {
return nullopt; return nullopt;
} }
} }
}
auto filepath = filesystem::u8path(path.toStdString()); auto filepath = filesystem::u8path(path.toStdString());
meta.isBaseTheme = filepath.extension() == ".obt"; meta.isBaseTheme = filepath.extension() == ".obt";
@@ -139,22 +152,27 @@ static bool ParseVarName(CFParser &cfp, QString &value)
int ret; int ret;
ret = cf_next_token_should_be(cfp, "(", ";", nullptr); ret = cf_next_token_should_be(cfp, "(", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
return false; return false;
}
ret = cf_next_token_should_be(cfp, "-", ";", nullptr); ret = cf_next_token_should_be(cfp, "-", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
return false; return false;
}
ret = cf_next_token_should_be(cfp, "-", ";", nullptr); ret = cf_next_token_should_be(cfp, "-", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
return false; return false;
if (!cf_next_token(cfp)) }
if (!cf_next_token(cfp)) {
return false; return false;
}
value = QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len); value = QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len);
ret = cf_next_token_should_be(cfp, ")", ";", nullptr); ret = cf_next_token_should_be(cfp, ")", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
return false; return false;
}
return !value.isEmpty(); return !value.isEmpty();
} }
@@ -166,35 +184,40 @@ static QColor ParseColor(CFParser &cfp)
QColor res(QColor::Invalid); QColor res(QColor::Invalid);
if (cf_token_is(cfp, "#")) { if (cf_token_is(cfp, "#")) {
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return res; return res;
}
color = strtol(cfp->cur_token->str.array, nullptr, 16); color = strtol(cfp->cur_token->str.array, nullptr, 16);
} else if (cf_token_is(cfp, "rgb")) { } else if (cf_token_is(cfp, "rgb")) {
int ret = cf_next_token_should_be(cfp, "(", ";", nullptr); int ret = cf_next_token_should_be(cfp, "(", ";", nullptr);
if (ret != PARSE_SUCCESS || !cf_next_token(cfp)) if (ret != PARSE_SUCCESS || !cf_next_token(cfp)) {
return res; return res;
}
array = cfp->cur_token->str.array; array = cfp->cur_token->str.array;
color |= strtol(array, nullptr, 10) << 16; color |= strtol(array, nullptr, 10) << 16;
ret = cf_next_token_should_be(cfp, ",", ";", nullptr); ret = cf_next_token_should_be(cfp, ",", ";", nullptr);
if (ret != PARSE_SUCCESS || !cf_next_token(cfp)) if (ret != PARSE_SUCCESS || !cf_next_token(cfp)) {
return res; return res;
}
array = cfp->cur_token->str.array; array = cfp->cur_token->str.array;
color |= strtol(array, nullptr, 10) << 8; color |= strtol(array, nullptr, 10) << 8;
ret = cf_next_token_should_be(cfp, ",", ";", nullptr); ret = cf_next_token_should_be(cfp, ",", ";", nullptr);
if (ret != PARSE_SUCCESS || !cf_next_token(cfp)) if (ret != PARSE_SUCCESS || !cf_next_token(cfp)) {
return res; return res;
}
array = cfp->cur_token->str.array; array = cfp->cur_token->str.array;
color |= strtol(array, nullptr, 10); color |= strtol(array, nullptr, 10);
ret = cf_next_token_should_be(cfp, ")", ";", nullptr); ret = cf_next_token_should_be(cfp, ")", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
return res; return res;
}
} else if (cf_token_is(cfp, "bikeshed")) { } else if (cf_token_is(cfp, "bikeshed")) {
color |= QRandomGenerator::global()->bounded(INT8_MAX) << 16; color |= QRandomGenerator::global()->bounded(INT8_MAX) << 16;
color |= QRandomGenerator::global()->bounded(INT8_MAX) << 8; color |= QRandomGenerator::global()->bounded(INT8_MAX) << 8;
@@ -208,14 +231,17 @@ static QColor ParseColor(CFParser &cfp)
static bool ParseMath(CFParser &cfp, QStringList &values, vector<OBSThemeVariable> &vars) static bool ParseMath(CFParser &cfp, QStringList &values, vector<OBSThemeVariable> &vars)
{ {
int ret = cf_next_token_should_be(cfp, "(", ";", nullptr); int ret = cf_next_token_should_be(cfp, "(", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
return false; return false;
if (!cf_next_token(cfp)) }
if (!cf_next_token(cfp)) {
return false; return false;
}
while (!cf_token_is(cfp, ")")) { while (!cf_token_is(cfp, ")")) {
if (cf_token_is(cfp, ";")) if (cf_token_is(cfp, ";")) {
break; break;
}
if (cf_token_is(cfp, "calc") || cf_token_is(cfp, "max") || cf_token_is(cfp, "min")) { if (cf_token_is(cfp, "calc") || cf_token_is(cfp, "max") || cf_token_is(cfp, "min")) {
/* Internal math operations do not have proper names. /* Internal math operations do not have proper names.
@@ -226,15 +252,17 @@ static bool ParseMath(CFParser &cfp, QStringList &values, vector<OBSThemeVariabl
var.name = QString("__unnamed_%1").arg(QRandomGenerator::global()->generate64()); var.name = QString("__unnamed_%1").arg(QRandomGenerator::global()->generate64());
OBSThemeVariable::VariableType varType; OBSThemeVariable::VariableType varType;
if (cf_token_is(cfp, "calc")) if (cf_token_is(cfp, "calc")) {
varType = OBSThemeVariable::Calc; varType = OBSThemeVariable::Calc;
else if (cf_token_is(cfp, "max")) } else if (cf_token_is(cfp, "max")) {
varType = OBSThemeVariable::Max; varType = OBSThemeVariable::Max;
else if (cf_token_is(cfp, "min")) } else if (cf_token_is(cfp, "min")) {
varType = OBSThemeVariable::Min; varType = OBSThemeVariable::Min;
}
if (!ParseMath(cfp, subvalues, vars)) if (!ParseMath(cfp, subvalues, vars)) {
return false; return false;
}
var.type = varType; var.type = varType;
var.value = subvalues; var.value = subvalues;
@@ -242,17 +270,19 @@ static bool ParseMath(CFParser &cfp, QStringList &values, vector<OBSThemeVariabl
vars.push_back(std::move(var)); vars.push_back(std::move(var));
} else if (cf_token_is(cfp, "var")) { } else if (cf_token_is(cfp, "var")) {
QString value; QString value;
if (!ParseVarName(cfp, value)) if (!ParseVarName(cfp, value)) {
return false; return false;
}
values << value; values << value;
} else { } else {
values << QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len); values << QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len);
} }
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return false; return false;
} }
}
return !values.isEmpty(); return !values.isEmpty();
} }
@@ -264,43 +294,54 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
std::vector<OBSThemeVariable> vars; std::vector<OBSThemeVariable> vars;
if (!cf_parser_parse(cfp, themeData, nullptr)) if (!cf_parser_parse(cfp, themeData, nullptr)) {
return vars;
if (!cf_token_is(cfp, "@") && !cf_go_to_token(cfp, "@", nullptr))
return vars;
while (cf_next_token(cfp)) {
if (cf_token_is(cfp, "OBSThemeVars"))
break;
if (!cf_go_to_token(cfp, "@", nullptr))
return vars; return vars;
} }
if (!cf_next_token(cfp)) if (!cf_token_is(cfp, "@") && !cf_go_to_token(cfp, "@", nullptr)) {
return {}; return vars;
}
if (!cf_token_is(cfp, "{")) while (cf_next_token(cfp)) {
if (cf_token_is(cfp, "OBSThemeVars")) {
break;
}
if (!cf_go_to_token(cfp, "@", nullptr)) {
return vars;
}
}
if (!cf_next_token(cfp)) {
return {}; return {};
}
if (!cf_token_is(cfp, "{")) {
return {};
}
for (;;) { for (;;) {
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return vars; return vars;
}
if (!cf_token_is(cfp, "-")) if (!cf_token_is(cfp, "-")) {
return vars; return vars;
}
ret = cf_next_token_should_be(cfp, "-", ";", nullptr); ret = cf_next_token_should_be(cfp, "-", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
continue; continue;
}
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return vars; return vars;
}
ret = cf_token_is_type(cfp, CFTOKEN_NAME, "key", nullptr); ret = cf_token_is_type(cfp, CFTOKEN_NAME, "key", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
break; break;
}
QString key = QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len); QString key = QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len);
OBSThemeVariable var; OBSThemeVariable var;
@@ -319,16 +360,19 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
} }
ret = cf_next_token_should_be(cfp, ":", ";", nullptr); ret = cf_next_token_should_be(cfp, ":", ";", nullptr);
if (ret != PARSE_SUCCESS) if (ret != PARSE_SUCCESS) {
continue; continue;
}
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return vars; return vars;
}
/* Special values passed to the theme by OBS are prefixed with 'obs', so we /* Special values passed to the theme by OBS are prefixed with 'obs', so we
* prevent theme variables from using it as a prefix. */ * prevent theme variables from using it as a prefix. */
if (key.startsWith("obs")) if (key.startsWith("obs")) {
continue; continue;
}
if (cfp->cur_token->type == CFTOKEN_NUM) { if (cfp->cur_token->type == CFTOKEN_NUM) {
const char *ch = cfp->cur_token->str.array; const char *ch = cfp->cur_token->str.array;
@@ -349,31 +393,35 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
} }
} else if (cf_token_is(cfp, "rgb") || cf_token_is(cfp, "#") || cf_token_is(cfp, "bikeshed")) { } else if (cf_token_is(cfp, "rgb") || cf_token_is(cfp, "#") || cf_token_is(cfp, "bikeshed")) {
QColor color = ParseColor(cfp); QColor color = ParseColor(cfp);
if (!color.isValid()) if (!color.isValid()) {
continue; continue;
}
var.value = color; var.value = color;
var.type = OBSThemeVariable::Color; var.type = OBSThemeVariable::Color;
} else if (cf_token_is(cfp, "var")) { } else if (cf_token_is(cfp, "var")) {
QString value; QString value;
if (!ParseVarName(cfp, value)) if (!ParseVarName(cfp, value)) {
continue; continue;
}
var.value = value; var.value = value;
var.type = OBSThemeVariable::Alias; var.type = OBSThemeVariable::Alias;
} else if (cf_token_is(cfp, "calc") || cf_token_is(cfp, "max") || cf_token_is(cfp, "min")) { } else if (cf_token_is(cfp, "calc") || cf_token_is(cfp, "max") || cf_token_is(cfp, "min")) {
QStringList values; QStringList values;
if (cf_token_is(cfp, "calc")) if (cf_token_is(cfp, "calc")) {
var.type = OBSThemeVariable::Calc; var.type = OBSThemeVariable::Calc;
else if (cf_token_is(cfp, "max")) } else if (cf_token_is(cfp, "max")) {
var.type = OBSThemeVariable::Max; var.type = OBSThemeVariable::Max;
else if (cf_token_is(cfp, "min")) } else if (cf_token_is(cfp, "min")) {
var.type = OBSThemeVariable::Min; var.type = OBSThemeVariable::Min;
}
if (!ParseMath(cfp, values, vars)) if (!ParseMath(cfp, values, vars)) {
continue; continue;
}
var.value = values; var.value = values;
} else { } else {
@@ -382,8 +430,9 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
var.value = QString::fromUtf8(strVal.Get()); var.value = QString::fromUtf8(strVal.Get());
} }
if (!cf_next_token(cfp)) if (!cf_next_token(cfp)) {
return vars; return vars;
}
if (cf_token_is(cfp, "!") && if (cf_token_is(cfp, "!") &&
cf_next_token_should_be(cfp, "editable", nullptr, nullptr) == PARSE_SUCCESS) { cf_next_token_should_be(cfp, "editable", nullptr, nullptr) == PARSE_SUCCESS) {
@@ -398,9 +447,10 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
vars.push_back(std::move(var)); vars.push_back(std::move(var));
if (!cf_token_is(cfp, ";") && !cf_go_to_token(cfp, ";", nullptr)) if (!cf_token_is(cfp, ";") && !cf_go_to_token(cfp, ";", nullptr)) {
return vars; return vars;
} }
}
return vars; return vars;
} }
@@ -420,10 +470,11 @@ void OBSApp::FindThemes()
QDirIterator it(QString::fromStdString(themeDir), filters, QDir::Files); QDirIterator it(QString::fromStdString(themeDir), filters, QDir::Files);
while (it.hasNext()) { while (it.hasNext()) {
auto theme = ParseThemeMeta(it.next()); auto theme = ParseThemeMeta(it.next());
if (theme && !themes.contains(theme->id)) if (theme && !themes.contains(theme->id)) {
themes[theme->id] = std::move(*theme); themes[theme->id] = std::move(*theme);
} }
} }
}
{ {
const std::string themeDir = App()->userConfigLocation.u8string() + "/obs-studio/themes"; const std::string themeDir = App()->userConfigLocation.u8string() + "/obs-studio/themes";
@@ -432,10 +483,11 @@ void OBSApp::FindThemes()
while (it.hasNext()) { while (it.hasNext()) {
auto theme = ParseThemeMeta(it.next()); auto theme = ParseThemeMeta(it.next());
if (theme && !themes.contains(theme->id)) if (theme && !themes.contains(theme->id)) {
themes[theme->id] = std::move(*theme); themes[theme->id] = std::move(*theme);
} }
} }
}
/* Build dependency tree for all themes, removing ones that have items missing. */ /* Build dependency tree for all themes, removing ones that have items missing. */
QSet<QString> invalid; QSet<QString> invalid;
@@ -476,8 +528,9 @@ void OBSApp::FindThemes()
} }
/* Mark this theme as a variant of first parent that is a base theme. */ /* Mark this theme as a variant of first parent that is a base theme. */
if (!theme.isBaseTheme && parent->isBaseTheme && theme.parent.isEmpty()) if (!theme.isBaseTheme && parent->isBaseTheme && theme.parent.isEmpty()) {
theme.parent = parent->id; theme.parent = parent->id;
}
theme.dependencies.push_front(parent->id); theme.dependencies.push_front(parent->id);
parentId = parent->extends; parentId = parent->extends;
@@ -498,8 +551,9 @@ void OBSApp::FindThemes()
static bool ResolveVariable(const QHash<QString, OBSThemeVariable> &vars, OBSThemeVariable &var) static bool ResolveVariable(const QHash<QString, OBSThemeVariable> &vars, OBSThemeVariable &var)
{ {
if (var.type != OBSThemeVariable::Alias) if (var.type != OBSThemeVariable::Alias) {
return true; return true;
}
QString key = var.value.toString(); QString key = var.value.toString();
while (vars[key].type == OBSThemeVariable::Alias) { while (vars[key].type == OBSThemeVariable::Alias) {
@@ -627,14 +681,15 @@ static QString EvalMath(const QHash<QString, OBSThemeVariable> &vars, const OBST
double val = numeric_limits<double>::quiet_NaN(); double val = numeric_limits<double>::quiet_NaN();
if (type == OBSThemeVariable::Calc) { if (type == OBSThemeVariable::Calc) {
if (opt == "+") if (opt == "+") {
val = d1 + d2; val = d1 + d2;
else if (opt == "-") } else if (opt == "-") {
val = d1 - d2; val = d1 - d2;
else if (opt == "*") } else if (opt == "*") {
val = d1 * d2; val = d1 * d2;
else if (opt == "/") } else if (opt == "/") {
val = d1 / d2; val = d1 / d2;
}
if (!isnormal(val)) { if (!isnormal(val)) {
blog(LOG_ERROR, "Invalid calc() resulted in non-normal number: %f %s %f = %f", d1, blog(LOG_ERROR, "Invalid calc() resulted in non-normal number: %f %s %f = %f", d1,
@@ -651,10 +706,11 @@ static QString EvalMath(const QHash<QString, OBSThemeVariable> &vars, const OBST
QString result = QString::number(val, 'f', isInteger ? 0 : -1); QString result = QString::number(val, 'f', isInteger ? 0 : -1);
/* Carry-over suffix */ /* Carry-over suffix */
if (!val1.suffix.isEmpty()) if (!val1.suffix.isEmpty()) {
result += val1.suffix; result += val1.suffix;
else if (!val2.suffix.isEmpty()) } else if (!val2.suffix.isEmpty()) {
result += val2.suffix; result += val2.suffix;
}
return result; return result;
} }
@@ -690,8 +746,9 @@ static QString PrepareQSS(const QHash<QString, OBSThemeVariable> &vars, const QS
for (const OBSThemeVariable &var_ : vars) { for (const OBSThemeVariable &var_ : vars) {
OBSThemeVariable var(var_); OBSThemeVariable var(var_);
if (!ResolveVariable(vars, var)) if (!ResolveVariable(vars, var)) {
continue; continue;
}
QString needle = needleTemplate.arg(var_.name); QString needle = needleTemplate.arg(var_.name);
QString replace; QString replace;
@@ -709,8 +766,9 @@ static QString PrepareQSS(const QHash<QString, OBSThemeVariable> &vars, const QS
bool isInteger = ceill(val) == val; bool isInteger = ceill(val) == val;
replace = QString::number(val, 'f', isInteger ? 0 : -1); replace = QString::number(val, 'f', isInteger ? 0 : -1);
if (!var.suffix.isEmpty()) if (!var.suffix.isEmpty()) {
replace += var.suffix; replace += var.suffix;
}
} else { } else {
replace = value.toString(); replace = value.toString();
} }
@@ -747,22 +805,27 @@ static QPalette PreparePalette(const QHash<QString, OBSThemeVariable> &vars, con
static QHash<QString, QPalette::ColorRole> roleMap; static QHash<QString, QPalette::ColorRole> roleMap;
static QHash<QString, QPalette::ColorGroup> groupMap; static QHash<QString, QPalette::ColorGroup> groupMap;
if (roleMap.empty()) if (roleMap.empty()) {
FillEnumMap<QPalette::ColorRole>(roleMap); FillEnumMap<QPalette::ColorRole>(roleMap);
if (groupMap.empty()) }
if (groupMap.empty()) {
FillEnumMap<QPalette::ColorGroup>(groupMap); FillEnumMap<QPalette::ColorGroup>(groupMap);
}
QPalette pal(defaultPalette); QPalette pal(defaultPalette);
for (const OBSThemeVariable &var_ : vars) { for (const OBSThemeVariable &var_ : vars) {
if (!var_.name.startsWith("palette_")) if (!var_.name.startsWith("palette_")) {
continue; continue;
if (var_.name.count("_") < 1 || var_.name.count("_") > 2) }
if (var_.name.count("_") < 1 || var_.name.count("_") > 2) {
continue; continue;
}
OBSThemeVariable var(var_); OBSThemeVariable var(var_);
if (!ResolveVariable(vars, var) || var.type != OBSThemeVariable::Color) if (!ResolveVariable(vars, var) || var.type != OBSThemeVariable::Color) {
continue; continue;
}
/* Determine role and optionally group based on name. /* Determine role and optionally group based on name.
* Format is: palette_<role>[_<group>] */ * Format is: palette_<role>[_<group>] */
@@ -816,8 +879,9 @@ static double getPaddingForDensityId(int id)
OBSTheme *OBSApp::GetTheme(const QString &name) OBSTheme *OBSApp::GetTheme(const QString &name)
{ {
if (!themes.contains(name)) if (!themes.contains(name)) {
return nullptr; return nullptr;
}
return &themes[name]; return &themes[name];
} }
@@ -825,8 +889,9 @@ OBSTheme *OBSApp::GetTheme(const QString &name)
bool OBSApp::SetTheme(const QString &name) bool OBSApp::SetTheme(const QString &name)
{ {
OBSTheme *theme = GetTheme(name); OBSTheme *theme = GetTheme(name);
if (!theme) if (!theme) {
return false; return false;
}
if (themeWatcher && themeWatcher->files().size() > 0) { if (themeWatcher && themeWatcher->files().size() > 0) {
themeWatcher->blockSignals(true); themeWatcher->blockSignals(true);
@@ -861,10 +926,12 @@ bool OBSApp::SetTheme(const QString &name)
/* Find and add high contrast adjustment layer if available */ /* Find and add high contrast adjustment layer if available */
if (HighContrastEnabled()) { if (HighContrastEnabled()) {
for (const OBSTheme &theme_ : themes) { for (const OBSTheme &theme_ : themes) {
if (!theme_.isHighContrast) if (!theme_.isHighContrast) {
continue; continue;
if (theme_.parent != theme->id) }
if (theme_.parent != theme->id) {
continue; continue;
}
themeIds << theme_.id; themeIds << theme_.id;
break; break;
} }
@@ -877,8 +944,9 @@ bool OBSApp::SetTheme(const QString &name)
QFile file(cur->location); QFile file(cur->location);
filenames << file.fileName(); filenames << file.fileName();
if (!file.open(QIODeviceBase::ReadOnly)) if (!file.open(QIODeviceBase::ReadOnly)) {
return false; return false;
}
const QByteArray content = file.readAll(); const QByteArray content = file.readAll();
for (OBSThemeVariable &var : ParseThemeVariables(content.constData())) { for (OBSThemeVariable &var : ParseThemeVariables(content.constData())) {
+33 -18
View File
@@ -17,9 +17,10 @@ inline size_t GetCallbackIdx(std::vector<OBSStudioCallback<T>> &callbacks, T cal
{ {
for (size_t i = 0; i < callbacks.size(); i++) { for (size_t i = 0; i < callbacks.size(); i++) {
OBSStudioCallback<T> curCB = callbacks[i]; OBSStudioCallback<T> curCB = callbacks[i];
if (curCB.callback == callback && curCB.private_data == private_data) if (curCB.callback == callback && curCB.private_data == private_data) {
return i; return i;
} }
}
return (size_t)-1; return (size_t)-1;
} }
@@ -46,10 +47,11 @@ void OBSStudioAPI::obs_frontend_get_scenes(struct obs_frontend_source_list *sour
OBSScene scene = GetOBSRef<OBSScene>(item); OBSScene scene = GetOBSRef<OBSScene>(item);
obs_source_t *source = obs_scene_get_source(scene); obs_source_t *source = obs_scene_get_source(scene);
if (obs_source_get_ref(source) != nullptr) if (obs_source_get_ref(source) != nullptr) {
da_push_back(sources->sources, &source); da_push_back(sources->sources, &source);
} }
} }
}
obs_source_t *OBSStudioAPI::obs_frontend_get_current_scene() obs_source_t *OBSStudioAPI::obs_frontend_get_current_scene()
{ {
@@ -77,10 +79,11 @@ void OBSStudioAPI::obs_frontend_get_transitions(struct obs_frontend_source_list
for (const auto &[uuid, transition] : main->transitions) { for (const auto &[uuid, transition] : main->transitions) {
obs_source_t *source = transition; obs_source_t *source = transition;
if (obs_source_get_ref(source) != nullptr) if (obs_source_get_ref(source) != nullptr) {
da_push_back(sources->sources, &source); da_push_back(sources->sources, &source);
} }
} }
}
obs_source_t *OBSStudioAPI::obs_frontend_get_current_transition() obs_source_t *OBSStudioAPI::obs_frontend_get_current_transition()
{ {
@@ -275,8 +278,9 @@ bool OBSStudioAPI::obs_frontend_recording_split_file()
bool OBSStudioAPI::obs_frontend_recording_add_chapter(const char *name) bool OBSStudioAPI::obs_frontend_recording_add_chapter(const char *name)
{ {
if (!os_atomic_load_bool(&recording_active) || os_atomic_load_bool(&recording_paused)) if (!os_atomic_load_bool(&recording_active) || os_atomic_load_bool(&recording_paused)) {
return false; return false;
}
proc_handler_t *ph = obs_output_get_proc_handler(main->outputHandler->fileOutput); proc_handler_t *ph = obs_output_get_proc_handler(main->outputHandler->fileOutput);
@@ -378,15 +382,17 @@ bool OBSStudioAPI::obs_frontend_add_custom_qdock(const char *id, void *dock)
void OBSStudioAPI::obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data) void OBSStudioAPI::obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data)
{ {
size_t idx = GetCallbackIdx(callbacks, callback, private_data); size_t idx = GetCallbackIdx(callbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1) {
callbacks.emplace_back(callback, private_data); callbacks.emplace_back(callback, private_data);
} }
}
void OBSStudioAPI::obs_frontend_remove_event_callback(obs_frontend_event_cb callback, void *private_data) void OBSStudioAPI::obs_frontend_remove_event_callback(obs_frontend_event_cb callback, void *private_data)
{ {
size_t idx = GetCallbackIdx(callbacks, callback, private_data); size_t idx = GetCallbackIdx(callbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1) {
return; return;
}
callbacks.erase(callbacks.begin() + idx); callbacks.erase(callbacks.begin() + idx);
} }
@@ -395,8 +401,9 @@ obs_output_t *OBSStudioAPI::obs_frontend_get_streaming_output()
{ {
auto multitrackVideo = main->outputHandler->multitrackVideo.get(); auto multitrackVideo = main->outputHandler->multitrackVideo.get();
auto mtvOutput = multitrackVideo ? obs_output_get_ref(multitrackVideo->StreamingOutput()) : nullptr; auto mtvOutput = multitrackVideo ? obs_output_get_ref(multitrackVideo->StreamingOutput()) : nullptr;
if (mtvOutput) if (mtvOutput) {
return mtvOutput; return mtvOutput;
}
OBSOutput output = main->outputHandler->streamOutput.Get(); OBSOutput output = main->outputHandler->streamOutput.Get();
return obs_output_get_ref(output); return obs_output_get_ref(output);
@@ -438,15 +445,16 @@ void OBSStudioAPI::obs_frontend_open_projector(const char *type, int monitor, co
name ? name : "", name ? name : "",
}; };
if (type) { if (type) {
if (astrcmpi(type, "Source") == 0) if (astrcmpi(type, "Source") == 0) {
proj.type = ProjectorType::Source; proj.type = ProjectorType::Source;
else if (astrcmpi(type, "Scene") == 0) } else if (astrcmpi(type, "Scene") == 0) {
proj.type = ProjectorType::Scene; proj.type = ProjectorType::Scene;
else if (astrcmpi(type, "StudioProgram") == 0) } else if (astrcmpi(type, "StudioProgram") == 0) {
proj.type = ProjectorType::StudioProgram; proj.type = ProjectorType::StudioProgram;
else if (astrcmpi(type, "Multiview") == 0) } else if (astrcmpi(type, "Multiview") == 0) {
proj.type = ProjectorType::Multiview; proj.type = ProjectorType::Multiview;
} }
}
QMetaObject::invokeMethod(main, "OpenSavedProjector", WaitConnection(), Q_ARG(SavedProjectorInfo *, &proj)); QMetaObject::invokeMethod(main, "OpenSavedProjector", WaitConnection(), Q_ARG(SavedProjectorInfo *, &proj));
} }
@@ -468,15 +476,17 @@ void OBSStudioAPI::obs_frontend_defer_save_end()
void OBSStudioAPI::obs_frontend_add_save_callback(obs_frontend_save_cb callback, void *private_data) void OBSStudioAPI::obs_frontend_add_save_callback(obs_frontend_save_cb callback, void *private_data)
{ {
size_t idx = GetCallbackIdx(saveCallbacks, callback, private_data); size_t idx = GetCallbackIdx(saveCallbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1) {
saveCallbacks.emplace_back(callback, private_data); saveCallbacks.emplace_back(callback, private_data);
} }
}
void OBSStudioAPI::obs_frontend_remove_save_callback(obs_frontend_save_cb callback, void *private_data) void OBSStudioAPI::obs_frontend_remove_save_callback(obs_frontend_save_cb callback, void *private_data)
{ {
size_t idx = GetCallbackIdx(saveCallbacks, callback, private_data); size_t idx = GetCallbackIdx(saveCallbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1) {
return; return;
}
saveCallbacks.erase(saveCallbacks.begin() + idx); saveCallbacks.erase(saveCallbacks.begin() + idx);
} }
@@ -484,15 +494,17 @@ void OBSStudioAPI::obs_frontend_remove_save_callback(obs_frontend_save_cb callba
void OBSStudioAPI::obs_frontend_add_preload_callback(obs_frontend_save_cb callback, void *private_data) void OBSStudioAPI::obs_frontend_add_preload_callback(obs_frontend_save_cb callback, void *private_data)
{ {
size_t idx = GetCallbackIdx(preloadCallbacks, callback, private_data); size_t idx = GetCallbackIdx(preloadCallbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1) {
preloadCallbacks.emplace_back(callback, private_data); preloadCallbacks.emplace_back(callback, private_data);
} }
}
void OBSStudioAPI::obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, void *private_data) void OBSStudioAPI::obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, void *private_data)
{ {
size_t idx = GetCallbackIdx(preloadCallbacks, callback, private_data); size_t idx = GetCallbackIdx(preloadCallbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1) {
return; return;
}
preloadCallbacks.erase(preloadCallbacks.begin() + idx); preloadCallbacks.erase(preloadCallbacks.begin() + idx);
} }
@@ -544,9 +556,10 @@ bool OBSStudioAPI::obs_frontend_preview_enabled()
void OBSStudioAPI::obs_frontend_set_preview_enabled(bool enable) void OBSStudioAPI::obs_frontend_set_preview_enabled(bool enable)
{ {
if (main->previewEnabled != enable) if (main->previewEnabled != enable) {
main->EnablePreviewDisplay(enable); main->EnablePreviewDisplay(enable);
} }
}
obs_source_t *OBSStudioAPI::obs_frontend_get_current_preview_scene() obs_source_t *OBSStudioAPI::obs_frontend_get_current_preview_scene()
{ {
@@ -666,10 +679,11 @@ void OBSStudioAPI::obs_frontend_get_canvases(obs_frontend_canvas_list *canvas_li
{ {
for (const auto &canvas : main->canvases) { for (const auto &canvas : main->canvases) {
obs_canvas_t *ref = obs_canvas_get_ref(canvas); obs_canvas_t *ref = obs_canvas_get_ref(canvas);
if (ref) if (ref) {
da_push_back(canvas_list->canvases, &ref); da_push_back(canvas_list->canvases, &ref);
} }
} }
}
obs_canvas_t *OBSStudioAPI::obs_frontend_add_canvas(const char *name, obs_video_info *ovi, int flags) obs_canvas_t *OBSStudioAPI::obs_frontend_add_canvas(const char *name, obs_video_info *ovi, int flags)
{ {
@@ -731,8 +745,9 @@ void OBSStudioAPI::on_save(obs_data_t *settings)
void OBSStudioAPI::on_event(enum obs_frontend_event event) void OBSStudioAPI::on_event(enum obs_frontend_event event)
{ {
if (main->disableSaving && event != OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP && if (main->disableSaving && event != OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP &&
event != OBS_FRONTEND_EVENT_EXIT) event != OBS_FRONTEND_EVENT_EXIT) {
return; return;
}
for (size_t i = callbacks.size(); i > 0; i--) { for (size_t i = callbacks.size(); i > 0; i--) {
auto cb = callbacks[i - 1]; auto cb = callbacks[i - 1];
+118 -59
View File
@@ -32,11 +32,13 @@ static char **convert_string_list(vector<string> &strings)
size += string_data_offset; size += string_data_offset;
for (auto &str : strings) for (auto &str : strings) {
size += str.size() + 1; size += str.size() + 1;
}
if (!size) if (!size) {
return 0; return 0;
}
out = (uint8_t *)bmalloc(size); out = (uint8_t *)bmalloc(size);
ptr_list = (char **)out; ptr_list = (char **)out;
@@ -73,8 +75,9 @@ void *obs_frontend_get_system_tray(void)
char **obs_frontend_get_scene_names(void) char **obs_frontend_get_scene_names(void)
{ {
if (!callbacks_valid()) if (!callbacks_valid()) {
return NULL; return NULL;
}
struct obs_frontend_source_list sources = {}; struct obs_frontend_source_list sources = {};
vector<string> names; vector<string> names;
@@ -92,9 +95,10 @@ char **obs_frontend_get_scene_names(void)
void obs_frontend_get_scenes(struct obs_frontend_source_list *sources) void obs_frontend_get_scenes(struct obs_frontend_source_list *sources)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_get_scenes(sources); c->obs_frontend_get_scenes(sources);
} }
}
obs_source_t *obs_frontend_get_current_scene(void) obs_source_t *obs_frontend_get_current_scene(void)
{ {
@@ -103,15 +107,17 @@ obs_source_t *obs_frontend_get_current_scene(void)
void obs_frontend_set_current_scene(obs_source_t *scene) void obs_frontend_set_current_scene(obs_source_t *scene)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_current_scene(scene); c->obs_frontend_set_current_scene(scene);
} }
}
void obs_frontend_get_transitions(struct obs_frontend_source_list *sources) void obs_frontend_get_transitions(struct obs_frontend_source_list *sources)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_get_transitions(sources); c->obs_frontend_get_transitions(sources);
} }
}
obs_source_t *obs_frontend_get_current_transition(void) obs_source_t *obs_frontend_get_current_transition(void)
{ {
@@ -120,9 +126,10 @@ obs_source_t *obs_frontend_get_current_transition(void)
void obs_frontend_set_current_transition(obs_source_t *transition) void obs_frontend_set_current_transition(obs_source_t *transition)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_current_transition(transition); c->obs_frontend_set_current_transition(transition);
} }
}
int obs_frontend_get_transition_duration(void) int obs_frontend_get_transition_duration(void)
{ {
@@ -131,15 +138,17 @@ int obs_frontend_get_transition_duration(void)
void obs_frontend_set_transition_duration(int duration) void obs_frontend_set_transition_duration(int duration)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_transition_duration(duration); c->obs_frontend_set_transition_duration(duration);
} }
}
void obs_frontend_release_tbar(void) void obs_frontend_release_tbar(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_release_tbar(); c->obs_frontend_release_tbar();
} }
}
int obs_frontend_get_tbar_position(void) int obs_frontend_get_tbar_position(void)
{ {
@@ -148,14 +157,16 @@ int obs_frontend_get_tbar_position(void)
void obs_frontend_set_tbar_position(int position) void obs_frontend_set_tbar_position(int position)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_tbar_position(position); c->obs_frontend_set_tbar_position(position);
} }
}
char **obs_frontend_get_scene_collections(void) char **obs_frontend_get_scene_collections(void)
{ {
if (!callbacks_valid()) if (!callbacks_valid()) {
return nullptr; return nullptr;
}
vector<string> strings; vector<string> strings;
c->obs_frontend_get_scene_collections(strings); c->obs_frontend_get_scene_collections(strings);
@@ -169,9 +180,10 @@ char *obs_frontend_get_current_scene_collection(void)
void obs_frontend_set_current_scene_collection(const char *collection) void obs_frontend_set_current_scene_collection(const char *collection)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_current_scene_collection(collection); c->obs_frontend_set_current_scene_collection(collection);
} }
}
bool obs_frontend_add_scene_collection(const char *name) bool obs_frontend_add_scene_collection(const char *name)
{ {
@@ -180,8 +192,9 @@ bool obs_frontend_add_scene_collection(const char *name)
char **obs_frontend_get_profiles(void) char **obs_frontend_get_profiles(void)
{ {
if (!callbacks_valid()) if (!callbacks_valid()) {
return nullptr; return nullptr;
}
vector<string> strings; vector<string> strings;
c->obs_frontend_get_profiles(strings); c->obs_frontend_get_profiles(strings);
@@ -200,39 +213,45 @@ char *obs_frontend_get_current_profile_path(void)
void obs_frontend_set_current_profile(const char *profile) void obs_frontend_set_current_profile(const char *profile)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_current_profile(profile); c->obs_frontend_set_current_profile(profile);
} }
}
void obs_frontend_create_profile(const char *name) void obs_frontend_create_profile(const char *name)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_create_profile(name); c->obs_frontend_create_profile(name);
} }
}
void obs_frontend_duplicate_profile(const char *name) void obs_frontend_duplicate_profile(const char *name)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_duplicate_profile(name); c->obs_frontend_duplicate_profile(name);
} }
}
void obs_frontend_delete_profile(const char *profile) void obs_frontend_delete_profile(const char *profile)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_delete_profile(profile); c->obs_frontend_delete_profile(profile);
} }
}
void obs_frontend_streaming_start(void) void obs_frontend_streaming_start(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_streaming_start(); c->obs_frontend_streaming_start();
} }
}
void obs_frontend_streaming_stop(void) void obs_frontend_streaming_stop(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_streaming_stop(); c->obs_frontend_streaming_stop();
} }
}
bool obs_frontend_streaming_active(void) bool obs_frontend_streaming_active(void)
{ {
@@ -241,15 +260,17 @@ bool obs_frontend_streaming_active(void)
void obs_frontend_recording_start(void) void obs_frontend_recording_start(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_recording_start(); c->obs_frontend_recording_start();
} }
}
void obs_frontend_recording_stop(void) void obs_frontend_recording_stop(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_recording_stop(); c->obs_frontend_recording_stop();
} }
}
bool obs_frontend_recording_active(void) bool obs_frontend_recording_active(void)
{ {
@@ -258,9 +279,10 @@ bool obs_frontend_recording_active(void)
void obs_frontend_recording_pause(bool pause) void obs_frontend_recording_pause(bool pause)
{ {
if (!!callbacks_valid()) if (!!callbacks_valid()) {
c->obs_frontend_recording_pause(pause); c->obs_frontend_recording_pause(pause);
} }
}
bool obs_frontend_recording_paused(void) bool obs_frontend_recording_paused(void)
{ {
@@ -279,21 +301,24 @@ bool obs_frontend_recording_add_chapter(const char *name)
void obs_frontend_replay_buffer_start(void) void obs_frontend_replay_buffer_start(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_replay_buffer_start(); c->obs_frontend_replay_buffer_start();
} }
}
void obs_frontend_replay_buffer_save(void) void obs_frontend_replay_buffer_save(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_replay_buffer_save(); c->obs_frontend_replay_buffer_save();
} }
}
void obs_frontend_replay_buffer_stop(void) void obs_frontend_replay_buffer_stop(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_replay_buffer_stop(); c->obs_frontend_replay_buffer_stop();
} }
}
bool obs_frontend_replay_buffer_active(void) bool obs_frontend_replay_buffer_active(void)
{ {
@@ -307,9 +332,10 @@ void *obs_frontend_add_tools_menu_qaction(const char *name)
void obs_frontend_add_tools_menu_item(const char *name, obs_frontend_cb callback, void *private_data) void obs_frontend_add_tools_menu_item(const char *name, obs_frontend_cb callback, void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_add_tools_menu_item(name, callback, private_data); c->obs_frontend_add_tools_menu_item(name, callback, private_data);
} }
}
bool obs_frontend_add_dock_by_id(const char *id, const char *title, void *widget) bool obs_frontend_add_dock_by_id(const char *id, const char *title, void *widget)
{ {
@@ -318,9 +344,10 @@ bool obs_frontend_add_dock_by_id(const char *id, const char *title, void *widget
void obs_frontend_remove_dock(const char *id) void obs_frontend_remove_dock(const char *id)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_remove_dock(id); c->obs_frontend_remove_dock(id);
} }
}
bool obs_frontend_add_custom_qdock(const char *id, void *dock) bool obs_frontend_add_custom_qdock(const char *id, void *dock)
{ {
@@ -329,15 +356,17 @@ bool obs_frontend_add_custom_qdock(const char *id, void *dock)
void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data) void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_add_event_callback(callback, private_data); c->obs_frontend_add_event_callback(callback, private_data);
} }
}
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, void *private_data) void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_remove_event_callback(callback, private_data); c->obs_frontend_remove_event_callback(callback, private_data);
} }
}
obs_output_t *obs_frontend_get_streaming_output(void) obs_output_t *obs_frontend_get_streaming_output(void)
{ {
@@ -378,63 +407,73 @@ config_t *obs_frontend_get_global_config(void)
void obs_frontend_open_projector(const char *type, int monitor, const char *geometry, const char *name) void obs_frontend_open_projector(const char *type, int monitor, const char *geometry, const char *name)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_open_projector(type, monitor, geometry, name); c->obs_frontend_open_projector(type, monitor, geometry, name);
} }
}
void obs_frontend_save(void) void obs_frontend_save(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_save(); c->obs_frontend_save();
} }
}
void obs_frontend_defer_save_begin(void) void obs_frontend_defer_save_begin(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_defer_save_begin(); c->obs_frontend_defer_save_begin();
} }
}
void obs_frontend_defer_save_end(void) void obs_frontend_defer_save_end(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_defer_save_end(); c->obs_frontend_defer_save_end();
} }
}
void obs_frontend_add_save_callback(obs_frontend_save_cb callback, void *private_data) void obs_frontend_add_save_callback(obs_frontend_save_cb callback, void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_add_save_callback(callback, private_data); c->obs_frontend_add_save_callback(callback, private_data);
} }
}
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, void *private_data) void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_remove_save_callback(callback, private_data); c->obs_frontend_remove_save_callback(callback, private_data);
} }
}
void obs_frontend_add_preload_callback(obs_frontend_save_cb callback, void *private_data) void obs_frontend_add_preload_callback(obs_frontend_save_cb callback, void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_add_preload_callback(callback, private_data); c->obs_frontend_add_preload_callback(callback, private_data);
} }
}
void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, void *private_data) void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_remove_preload_callback(callback, private_data); c->obs_frontend_remove_preload_callback(callback, private_data);
} }
}
void obs_frontend_push_ui_translation(obs_frontend_translate_ui_cb translate) void obs_frontend_push_ui_translation(obs_frontend_translate_ui_cb translate)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_push_ui_translation(translate); c->obs_frontend_push_ui_translation(translate);
} }
}
void obs_frontend_pop_ui_translation(void) void obs_frontend_pop_ui_translation(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_pop_ui_translation(); c->obs_frontend_pop_ui_translation();
} }
}
obs_service_t *obs_frontend_get_streaming_service(void) obs_service_t *obs_frontend_get_streaming_service(void)
{ {
@@ -443,15 +482,17 @@ obs_service_t *obs_frontend_get_streaming_service(void)
void obs_frontend_set_streaming_service(obs_service_t *service) void obs_frontend_set_streaming_service(obs_service_t *service)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_streaming_service(service); c->obs_frontend_set_streaming_service(service);
} }
}
void obs_frontend_save_streaming_service(void) void obs_frontend_save_streaming_service(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_save_streaming_service(); c->obs_frontend_save_streaming_service();
} }
}
bool obs_frontend_preview_program_mode_active(void) bool obs_frontend_preview_program_mode_active(void)
{ {
@@ -460,15 +501,17 @@ bool obs_frontend_preview_program_mode_active(void)
void obs_frontend_set_preview_program_mode(bool enable) void obs_frontend_set_preview_program_mode(bool enable)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_preview_program_mode(enable); c->obs_frontend_set_preview_program_mode(enable);
} }
}
void obs_frontend_preview_program_trigger_transition(void) void obs_frontend_preview_program_trigger_transition(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_preview_program_trigger_transition(); c->obs_frontend_preview_program_trigger_transition();
} }
}
bool obs_frontend_preview_enabled(void) bool obs_frontend_preview_enabled(void)
{ {
@@ -477,9 +520,10 @@ bool obs_frontend_preview_enabled(void)
void obs_frontend_set_preview_enabled(bool enable) void obs_frontend_set_preview_enabled(bool enable)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_preview_enabled(enable); c->obs_frontend_set_preview_enabled(enable);
} }
}
obs_source_t *obs_frontend_get_current_preview_scene(void) obs_source_t *obs_frontend_get_current_preview_scene(void)
{ {
@@ -488,21 +532,24 @@ obs_source_t *obs_frontend_get_current_preview_scene(void)
void obs_frontend_set_current_preview_scene(obs_source_t *scene) void obs_frontend_set_current_preview_scene(obs_source_t *scene)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_set_current_preview_scene(scene); c->obs_frontend_set_current_preview_scene(scene);
} }
}
void obs_frontend_take_screenshot(void) void obs_frontend_take_screenshot(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_take_screenshot(); c->obs_frontend_take_screenshot();
} }
}
void obs_frontend_take_source_screenshot(obs_source_t *source) void obs_frontend_take_source_screenshot(obs_source_t *source)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_take_source_screenshot(source); c->obs_frontend_take_source_screenshot(source);
} }
}
obs_output_t *obs_frontend_get_virtualcam_output(void) obs_output_t *obs_frontend_get_virtualcam_output(void)
{ {
@@ -511,15 +558,17 @@ obs_output_t *obs_frontend_get_virtualcam_output(void)
void obs_frontend_start_virtualcam(void) void obs_frontend_start_virtualcam(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_start_virtualcam(); c->obs_frontend_start_virtualcam();
} }
}
void obs_frontend_stop_virtualcam(void) void obs_frontend_stop_virtualcam(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_stop_virtualcam(); c->obs_frontend_stop_virtualcam();
} }
}
bool obs_frontend_virtualcam_active(void) bool obs_frontend_virtualcam_active(void)
{ {
@@ -528,33 +577,38 @@ bool obs_frontend_virtualcam_active(void)
void obs_frontend_reset_video(void) void obs_frontend_reset_video(void)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_reset_video(); c->obs_frontend_reset_video();
} }
}
void obs_frontend_open_source_properties(obs_source_t *source) void obs_frontend_open_source_properties(obs_source_t *source)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_open_source_properties(source); c->obs_frontend_open_source_properties(source);
} }
}
void obs_frontend_open_source_filters(obs_source_t *source) void obs_frontend_open_source_filters(obs_source_t *source)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_open_source_filters(source); c->obs_frontend_open_source_filters(source);
} }
}
void obs_frontend_open_source_interaction(obs_source_t *source) void obs_frontend_open_source_interaction(obs_source_t *source)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_open_source_interaction(source); c->obs_frontend_open_source_interaction(source);
} }
}
void obs_frontend_open_sceneitem_edit_transform(obs_sceneitem_t *item) void obs_frontend_open_sceneitem_edit_transform(obs_sceneitem_t *item)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_open_sceneitem_edit_transform(item); c->obs_frontend_open_sceneitem_edit_transform(item);
} }
}
char *obs_frontend_get_current_record_output_path(void) char *obs_frontend_get_current_record_output_path(void)
{ {
@@ -589,15 +643,17 @@ char *obs_frontend_get_last_replay(void)
void obs_frontend_add_undo_redo_action(const char *name, const undo_redo_cb undo, const undo_redo_cb redo, void obs_frontend_add_undo_redo_action(const char *name, const undo_redo_cb undo, const undo_redo_cb redo,
const char *undo_data, const char *redo_data, bool repeatable) const char *undo_data, const char *redo_data, bool repeatable)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_add_undo_redo_action(name, undo, redo, undo_data, redo_data, repeatable); c->obs_frontend_add_undo_redo_action(name, undo, redo, undo_data, redo_data, repeatable);
} }
}
void obs_frontend_get_canvases(obs_frontend_canvas_list *canvas_list) void obs_frontend_get_canvases(obs_frontend_canvas_list *canvas_list)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
c->obs_frontend_get_canvases(canvas_list); c->obs_frontend_get_canvases(canvas_list);
} }
}
obs_canvas_t *obs_frontend_add_canvas(const char *name, obs_video_info *ovi, int flags) obs_canvas_t *obs_frontend_add_canvas(const char *name, obs_video_info *ovi, int flags)
{ {
@@ -611,19 +667,22 @@ bool obs_frontend_remove_canvas(obs_canvas_t *canvas)
void obs_frontend_copy_sceneitem(obs_sceneitem_t *item) void obs_frontend_copy_sceneitem(obs_sceneitem_t *item)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
return c->obs_frontend_copy_sceneitem(item); return c->obs_frontend_copy_sceneitem(item);
} }
}
bool obs_frontend_can_paste_sceneitem(bool duplicate) bool obs_frontend_can_paste_sceneitem(bool duplicate)
{ {
if (!callbacks_valid()) if (!callbacks_valid()) {
return false; return false;
}
return c->obs_frontend_can_paste_sceneitem(duplicate); return c->obs_frontend_can_paste_sceneitem(duplicate);
} }
void obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate) void obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate)
{ {
if (callbacks_valid()) if (callbacks_valid()) {
return c->obs_frontend_paste_sceneitem(scene, duplicate); return c->obs_frontend_paste_sceneitem(scene, duplicate);
} }
}
+3 -2
View File
@@ -44,10 +44,11 @@ void AbsoluteSlider::mouseMoveEvent(QMouseEvent *event)
{ {
int val = posToRangeValue(event); int val = posToRangeValue(event);
if (val > maximum()) if (val > maximum()) {
val = maximum(); val = maximum();
else if (val < minimum()) } else if (val < minimum()) {
val = minimum(); val = minimum();
}
emit absoluteSliderHovered(val); emit absoluteSliderHovered(val);
+2 -1
View File
@@ -21,8 +21,9 @@ void AudioCaptureToolbar::Init()
ui->activateButton = nullptr; ui->activateButton = nullptr;
obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio"); obs_module_t *mod = get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio");
if (!mod) if (!mod) {
return; return;
}
const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device"); const char *device_str = get_os_text(mod, "Device", "CoreAudio.Device", "Device");
ui->deviceLabel->setText(device_str); ui->deviceLabel->setText(device_str);
+2 -1
View File
@@ -31,8 +31,9 @@ int FillPropertyCombo(QComboBox *c, obs_property_t *p, const std::string &cur_id
id = val ? val : ""; id = val ? val : "";
} }
if (cur_id == id) if (cur_id == id) {
cur_idx = (int)i; cur_idx = (int)i;
}
c->addItem(name, id.c_str()); c->addItem(name, id.c_str());
} }
+2 -1
View File
@@ -18,8 +18,9 @@ DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source)
active = obs_data_get_bool(settings, "active"); active = obs_data_get_bool(settings, "active");
obs_module_t *mod = obs_get_module("win-dshow"); obs_module_t *mod = obs_get_module("win-dshow");
if (!mod) if (!mod) {
return; return;
}
activateText = obs_module_get_locale_text(mod, "Activate"); activateText = obs_module_get_locale_text(mod, "Activate");
deactivateText = obs_module_get_locale_text(mod, "Deactivate"); deactivateText = obs_module_get_locale_text(mod, "Deactivate");
@@ -21,8 +21,9 @@ void DisplayCaptureToolbar::Init()
ui->activateButton = nullptr; ui->activateButton = nullptr;
obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture");
if (!mod) if (!mod) {
return; return;
}
const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen"); const char *device_str = get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen");
ui->deviceLabel->setText(device_str); ui->deviceLabel->setText(device_str);
+3 -2
View File
@@ -18,8 +18,9 @@ void FocusList::dragMoveEvent(QDragMoveEvent *event)
QPoint pos = event->position().toPoint(); QPoint pos = event->position().toPoint();
int itemRow = row(itemAt(pos)); int itemRow = row(itemAt(pos));
if ((itemRow == currentRow() + 1) || (currentRow() == count() - 1 && itemRow == -1)) if ((itemRow == currentRow() + 1) || (currentRow() == count() - 1 && itemRow == -1)) {
event->ignore(); event->ignore();
else } else {
QListWidget::dragMoveEvent(event); QListWidget::dragMoveEvent(event);
} }
}
+2 -1
View File
@@ -17,8 +17,9 @@ GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source)
ui->setupUi(this); ui->setupUi(this);
obs_module_t *mod = obs_get_module("win-capture"); obs_module_t *mod = obs_get_module("win-capture");
if (!mod) if (!mod) {
return; return;
}
ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode")); ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode"));
ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window")); ui->windowLabel->setText(obs_module_get_locale_text(mod, "WindowCapture.Window"));
+2 -1
View File
@@ -35,8 +35,9 @@ void ImageSourceToolbar::on_browse_clicked()
const char *default_path = obs_property_path_default_path(p); const char *default_path = obs_property_path_default_path(p);
QString startDir = ui->path->text(); QString startDir = ui->path->text();
if (startDir.isEmpty()) if (startDir.isEmpty()) {
startDir = default_path; startDir = default_path;
}
QString path = OpenFile(this, desc, startDir, filter); QString path = OpenFile(this, desc, startDir, filter);
if (path.isEmpty()) { if (path.isEmpty()) {
+25 -14
View File
@@ -180,18 +180,21 @@ void MediaControls::SeekTimerCallback()
void MediaControls::StartMediaTimer() void MediaControls::StartMediaTimer()
{ {
if (isSlideshow) if (isSlideshow) {
return; return;
}
if (!mediaTimer.isActive()) if (!mediaTimer.isActive()) {
mediaTimer.start(16); mediaTimer.start(16);
} }
}
void MediaControls::StopMediaTimer() void MediaControls::StopMediaTimer()
{ {
if (mediaTimer.isActive()) if (mediaTimer.isActive()) {
mediaTimer.stop(); mediaTimer.stop();
} }
}
void MediaControls::SetPlayingState() void MediaControls::SetPlayingState()
{ {
@@ -288,11 +291,12 @@ void MediaControls::RefreshControls()
break; break;
} }
if (isSlideshow) if (isSlideshow) {
UpdateSlideCounter(); UpdateSlideCounter();
else } else {
SetSliderPosition(); SetSliderPosition();
} }
}
OBSSource MediaControls::GetSource() OBSSource MediaControls::GetSource()
{ {
@@ -333,10 +337,11 @@ void MediaControls::SetSliderPosition()
float sliderPosition; float sliderPosition;
if (duration) if (duration) {
sliderPosition = (time / duration) * (float)ui->slider->maximum(); sliderPosition = (time / duration) * (float)ui->slider->maximum();
else } else {
sliderPosition = 0.0f; sliderPosition = 0.0f;
}
ui->slider->setValue((int)sliderPosition); ui->slider->setValue((int)sliderPosition);
UpdateLabels((int)sliderPosition); UpdateLabels((int)sliderPosition);
@@ -446,16 +451,18 @@ void MediaControls::on_durationLabel_clicked()
config_set_bool(App()->GetUserConfig(), "BasicWindow", "MediaControlsCountdownTimer", countDownTimer); config_set_bool(App()->GetUserConfig(), "BasicWindow", "MediaControlsCountdownTimer", countDownTimer);
if (MediaPaused()) if (MediaPaused()) {
SetSliderPosition(); SetSliderPosition();
} }
}
void MediaControls::MoveSliderFoward(int seconds) void MediaControls::MoveSliderFoward(int seconds)
{ {
OBSSource source = OBSGetStrongRef(weakSource); OBSSource source = OBSGetStrongRef(weakSource);
if (!source) if (!source) {
return; return;
}
int ms = obs_source_media_get_time(source); int ms = obs_source_media_get_time(source);
ms += seconds * 1000; ms += seconds * 1000;
@@ -468,8 +475,9 @@ void MediaControls::MoveSliderBackwards(int seconds)
{ {
OBSSource source = OBSGetStrongRef(weakSource); OBSSource source = OBSGetStrongRef(weakSource);
if (!source) if (!source) {
return; return;
}
int ms = obs_source_media_get_time(source); int ms = obs_source_media_get_time(source);
ms -= seconds * 1000; ms -= seconds * 1000;
@@ -480,13 +488,15 @@ void MediaControls::MoveSliderBackwards(int seconds)
void MediaControls::UpdateSlideCounter() void MediaControls::UpdateSlideCounter()
{ {
if (!isSlideshow) if (!isSlideshow) {
return; return;
}
OBSSource source = OBSGetStrongRef(weakSource); OBSSource source = OBSGetStrongRef(weakSource);
if (!source) if (!source) {
return; return;
}
proc_handler_t *ph = obs_source_get_proc_handler(source); proc_handler_t *ph = obs_source_get_proc_handler(source);
calldata_t cd = {}; calldata_t cd = {};
@@ -521,8 +531,9 @@ void MediaControls::UpdateLabels(int val)
ui->timerLabel->setText(FormatSeconds((int)(time / 1000.0f))); ui->timerLabel->setText(FormatSeconds((int)(time / 1000.0f)));
if (!countDownTimer) if (!countDownTimer) {
ui->durationLabel->setText(FormatSeconds((int)(duration / 1000.0f))); ui->durationLabel->setText(FormatSeconds((int)(duration / 1000.0f)));
else } else {
ui->durationLabel->setText(QString("-") + FormatSeconds((int)((duration - time) / 1000.0f))); ui->durationLabel->setText(QString("-") + FormatSeconds((int)((duration - time) / 1000.0f)));
} }
}
+3 -2
View File
@@ -26,10 +26,11 @@ void MenuButton::keyPressEvent(QKeyEvent *event)
void MenuButton::mousePressEvent(QMouseEvent *event) void MenuButton::mousePressEvent(QMouseEvent *event)
{ {
if (menu()) { if (menu()) {
if (width() - event->pos().x() <= 30) if (width() - event->pos().x() <= 30) {
showMenu(); showMenu();
else } else {
setDown(true); setDown(true);
}
} else { } else {
QPushButton::mousePressEvent(event); QPushButton::mousePressEvent(event);
} }
+57 -31
View File
@@ -14,9 +14,10 @@ Multiview::~Multiview()
{ {
for (OBSWeakSource &weakSrc : multiviewScenes) { for (OBSWeakSource &weakSrc : multiviewScenes) {
OBSSource src = OBSGetStrongRef(weakSrc); OBSSource src = OBSGetStrongRef(weakSrc);
if (src) if (src) {
obs_source_dec_showing(src); obs_source_dec_showing(src);
} }
}
obs_enter_graphics(); obs_enter_graphics();
gs_vertexbuffer_destroy(actionSafeMargin); gs_vertexbuffer_destroy(actionSafeMargin);
@@ -161,8 +162,9 @@ void Multiview::Update(MultiviewLayout multiviewLayout, bool drawLabel, bool dra
OBSDataAutoRelease data = obs_source_get_private_settings(src); OBSDataAutoRelease data = obs_source_get_private_settings(src);
obs_data_set_default_bool(data, "show_in_multiview", true); obs_data_set_default_bool(data, "show_in_multiview", true);
if (!obs_data_get_bool(data, "show_in_multiview")) if (!obs_data_get_bool(data, "show_in_multiview")) {
continue; continue;
}
updatedScenes.emplace_back(OBSGetWeakRef(src)); updatedScenes.emplace_back(OBSGetWeakRef(src));
obs_source_inc_showing(src); obs_source_inc_showing(src);
@@ -174,9 +176,10 @@ void Multiview::Update(MultiviewLayout multiviewLayout, bool drawLabel, bool dra
for (OBSWeakSource &weakSrc : multiviewScenes) { for (OBSWeakSource &weakSrc : multiviewScenes) {
OBSSource src = OBSGetStrongRef(weakSrc); OBSSource src = OBSGetStrongRef(weakSrc);
if (src) if (src) {
obs_source_dec_showing(src); obs_source_dec_showing(src);
} }
}
multiviewScenes = std::move(updatedScenes); multiviewScenes = std::move(updatedScenes);
multiviewLabels = std::move(updatedLabels); multiviewLabels = std::move(updatedLabels);
@@ -234,8 +237,9 @@ void Multiview::Render(uint32_t cx, uint32_t cy)
gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color"); gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color");
gs_effect_set_color(color, colorVal); gs_effect_set_color(color, colorVal);
while (gs_effect_loop(solid, "Solid")) while (gs_effect_loop(solid, "Solid")) {
gs_draw_sprite(nullptr, 0, (uint32_t)cx, (uint32_t)cy); gs_draw_sprite(nullptr, 0, (uint32_t)cx, (uint32_t)cy);
}
}; };
auto setRegion = [&](float bx, float by, float cx, float cy) { auto setRegion = [&](float bx, float by, float cx, float cy) {
@@ -265,14 +269,16 @@ void Multiview::Render(uint32_t cx, uint32_t cy)
case MultiviewLayout::VERTICAL_LEFT_8_SCENES: case MultiviewLayout::VERTICAL_LEFT_8_SCENES:
sourceX = pvwprgCX; sourceX = pvwprgCX;
sourceY = (i / 2) * scenesCY; sourceY = (i / 2) * scenesCY;
if (i % 2 != 0) if (i % 2 != 0) {
sourceX += scenesCX; sourceX += scenesCX;
}
break; break;
case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: case MultiviewLayout::VERTICAL_RIGHT_8_SCENES:
sourceX = 0; sourceX = 0;
sourceY = (i / 2) * scenesCY; sourceY = (i / 2) * scenesCY;
if (i % 2 != 0) if (i % 2 != 0) {
sourceX = scenesCX; sourceX = scenesCX;
}
break; break;
case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES:
if (i < 4) { if (i < 4) {
@@ -404,10 +410,11 @@ void Multiview::Render(uint32_t cx, uint32_t cy)
// We have a source. Now chose the proper highlight color // We have a source. Now chose the proper highlight color
uint32_t colorVal = outerColor; uint32_t colorVal = outerColor;
if (src == programSrc) if (src == programSrc) {
colorVal = programColor; colorVal = programColor;
else if (src == previewSrc) } else if (src == previewSrc) {
colorVal = studioMode ? previewColor : programColor; colorVal = studioMode ? previewColor : programColor;
}
// Paint the background // Paint the background
paintAreaWithColor(sourceX, sourceY, scenesCX, scenesCY, colorVal); paintAreaWithColor(sourceX, sourceY, scenesCX, scenesCY, colorVal);
@@ -427,12 +434,14 @@ void Multiview::Render(uint32_t cx, uint32_t cy)
/* ----------- */ /* ----------- */
// Render the label // Render the label
if (!drawLabel) if (!drawLabel) {
continue; continue;
}
obs_source *label = multiviewLabels[i + 2]; obs_source *label = multiviewLabels[i + 2];
if (!label) if (!label) {
continue; continue;
}
offset = labelOffset(multiviewLayout, label, scenesCX); offset = labelOffset(multiviewLayout, label, scenesCX);
@@ -470,10 +479,11 @@ void Multiview::Render(uint32_t cx, uint32_t cy)
gs_matrix_translate3f(sourceX, sourceY, 0.0f); gs_matrix_translate3f(sourceX, sourceY, 0.0f);
gs_matrix_scale3f(ppiScaleX, ppiScaleY, 1.0f); gs_matrix_scale3f(ppiScaleX, ppiScaleY, 1.0f);
setRegion(sourceX, sourceY, ppiCX, ppiCY); setRegion(sourceX, sourceY, ppiCX, ppiCY);
if (studioMode) if (studioMode) {
obs_source_video_render(previewSrc); obs_source_video_render(previewSrc);
else } else {
obs_render_main_texture(); obs_render_main_texture();
}
if (drawSafeArea) { if (drawSafeArea) {
RenderSafeAreas(actionSafeMargin, targetCX, targetCY); RenderSafeAreas(actionSafeMargin, targetCX, targetCY);
@@ -550,8 +560,9 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
{ {
int pos = -1; int pos = -1;
QWidget *rec = QApplication::activeWindow(); QWidget *rec = QApplication::activeWindow();
if (!rec) if (!rec) {
return nullptr; return nullptr;
}
int cx = rec->width(); int cx = rec->width();
int cy = rec->height(); int cy = rec->height();
int minX = 0; int minX = 0;
@@ -571,8 +582,9 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
} }
minY = cy / 2; minY = cy / 2;
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = (x - minX) / ((maxX - minX) / 6); pos = (x - minX) / ((maxX - minX) / 6);
pos += ((y - minY) / ((maxY - minY) / 3)) * 6; pos += ((y - minY) / ((maxY - minY) / 3)) * 6;
@@ -590,8 +602,9 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
minY = (cy / 2) - (validY / 6); minY = (cy / 2) - (validY / 6);
} }
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = (x - minX) / ((maxX - minX) / 6); pos = (x - minX) / ((maxX - minX) / 6);
pos += ((y - minY) / ((maxY - minY) / 4)) * 6; pos += ((y - minY) / ((maxY - minY) / 4)) * 6;
@@ -609,12 +622,14 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
minX = cx / 2; minX = cx / 2;
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = 2 * ((y - minY) / ((maxY - minY) / 4)); pos = 2 * ((y - minY) / ((maxY - minY) / 4));
if (x > minX + ((maxX - minX) / 2)) if (x > minX + ((maxX - minX) / 2)) {
pos++; pos++;
}
break; break;
case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: case MultiviewLayout::VERTICAL_RIGHT_8_SCENES:
if (float(cx) / float(cy) > ratio) { if (float(cx) / float(cy) > ratio) {
@@ -628,12 +643,14 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
maxX = (cx / 2); maxX = (cx / 2);
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = 2 * ((y - minY) / ((maxY - minY) / 4)); pos = 2 * ((y - minY) / ((maxY - minY) / 4));
if (x > minX + ((maxX - minX) / 2)) if (x > minX + ((maxX - minX) / 2)) {
pos++; pos++;
}
break; break;
case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES:
if (float(cx) / float(cy) > ratio) { if (float(cx) / float(cy) > ratio) {
@@ -647,12 +664,14 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
maxY = (cy / 2); maxY = (cy / 2);
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = (x - minX) / ((maxX - minX) / 4); pos = (x - minX) / ((maxX - minX) / 4);
if (y > minY + ((maxY - minY) / 2)) if (y > minY + ((maxY - minY) / 2)) {
pos += 4; pos += 4;
}
break; break;
case MultiviewLayout::SCENES_ONLY_4_SCENES: case MultiviewLayout::SCENES_ONLY_4_SCENES:
if (float(cx) / float(cy) > ratio) { if (float(cx) / float(cy) > ratio) {
@@ -665,8 +684,9 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
minY = (cy / 2) - (validY / 2); minY = (cy / 2) - (validY / 2);
} }
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = (x - minX) / ((maxX - minX) / 2); pos = (x - minX) / ((maxX - minX) / 2);
pos += ((y - minY) / ((maxY - minY) / 2)) * 2; pos += ((y - minY) / ((maxY - minY) / 2)) * 2;
@@ -683,8 +703,9 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
minY = (cy / 2) - (validY / 2); minY = (cy / 2) - (validY / 2);
} }
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = (x - minX) / ((maxX - minX) / 3); pos = (x - minX) / ((maxX - minX) / 3);
pos += ((y - minY) / ((maxY - minY) / 3)) * 3; pos += ((y - minY) / ((maxY - minY) / 3)) * 3;
@@ -701,8 +722,9 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
minY = (cy / 2) - (validY / 2); minY = (cy / 2) - (validY / 2);
} }
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = (x - minX) / ((maxX - minX) / 4); pos = (x - minX) / ((maxX - minX) / 4);
pos += ((y - minY) / ((maxY - minY) / 4)) * 4; pos += ((y - minY) / ((maxY - minY) / 4)) * 4;
@@ -719,8 +741,9 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
minY = (cy / 2) - (validY / 2); minY = (cy / 2) - (validY / 2);
} }
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
}
pos = (x - minX) / ((maxX - minX) / 5); pos = (x - minX) / ((maxX - minX) / 5);
pos += ((y - minY) / ((maxY - minY) / 5)) * 5; pos += ((y - minY) / ((maxY - minY) / 5)) * 5;
@@ -738,16 +761,19 @@ OBSSource Multiview::GetSourceByPosition(int x, int y)
minY = (cy / 2); minY = (cy / 2);
if (x < minX || x > maxX || y < minY || y > maxY) if (x < minX || x > maxX || y < minY || y > maxY) {
break; break;
pos = (x - minX) / ((maxX - minX) / 4);
if (y > minY + ((maxY - minY) / 2))
pos += 4;
} }
if (pos < 0 || pos >= (int)multiviewScenes.size()) pos = (x - minX) / ((maxX - minX) / 4);
if (y > minY + ((maxY - minY) / 2)) {
pos += 4;
}
}
if (pos < 0 || pos >= (int)multiviewScenes.size()) {
return nullptr; return nullptr;
}
return OBSGetStrongRef(multiviewScenes[pos]); return OBSGetStrongRef(multiviewScenes[pos]);
} }
+3 -2
View File
@@ -17,9 +17,10 @@ protected:
* able to manually get into the partial state. */ * able to manually get into the partial state. */
void nextCheckState() override void nextCheckState() override
{ {
if (checkState() != Qt::Checked) if (checkState() != Qt::Checked) {
setCheckState(Qt::Checked); setCheckState(Qt::Checked);
else } else {
setCheckState(Qt::Unchecked); setCheckState(Qt::Unchecked);
} }
}
}; };
+30 -17
View File
@@ -40,8 +40,9 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) : source(
percent = new QSpinBox(); percent = new QSpinBox();
forceMono = new QCheckBox(); forceMono = new QCheckBox();
balance = new BalanceSlider(); balance = new BalanceSlider();
if (obs_audio_monitoring_available()) if (obs_audio_monitoring_available()) {
monitoringType = new QComboBox(); monitoringType = new QComboBox();
}
syncOffset = new QSpinBox(); syncOffset = new QSpinBox();
mixer1 = new QCheckBox(); mixer1 = new QCheckBox();
mixer2 = new QCheckBox(); mixer2 = new QCheckBox();
@@ -57,8 +58,9 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) : source(
sigs.emplace_back(handler, "volume", OBSSourceVolumeChanged, this); sigs.emplace_back(handler, "volume", OBSSourceVolumeChanged, this);
sigs.emplace_back(handler, "audio_sync", OBSSourceSyncChanged, this); sigs.emplace_back(handler, "audio_sync", OBSSourceSyncChanged, this);
sigs.emplace_back(handler, "update_flags", OBSSourceFlagsChanged, this); sigs.emplace_back(handler, "update_flags", OBSSourceFlagsChanged, this);
if (obs_audio_monitoring_available()) if (obs_audio_monitoring_available()) {
sigs.emplace_back(handler, "audio_monitoring", OBSSourceMonitoringTypeChanged, this); sigs.emplace_back(handler, "audio_monitoring", OBSSourceMonitoringTypeChanged, this);
}
sigs.emplace_back(handler, "audio_mixers", OBSSourceMixersChanged, this); sigs.emplace_back(handler, "audio_mixers", OBSSourceMixersChanged, this);
sigs.emplace_back(handler, "audio_balance", OBSSourceBalanceChanged, this); sigs.emplace_back(handler, "audio_balance", OBSSourceBalanceChanged, this);
sigs.emplace_back(handler, "rename", OBSSourceRenamed, this); sigs.emplace_back(handler, "rename", OBSSourceRenamed, this);
@@ -87,8 +89,9 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) : source(
bool isActive = obs_source_active(source) && obs_source_audio_active(source); bool isActive = obs_source_active(source) && obs_source_audio_active(source);
active->setText(isActive ? QTStr("Basic.Stats.Status.Active") : QTStr("Basic.Stats.Status.Inactive")); active->setText(isActive ? QTStr("Basic.Stats.Status.Active") : QTStr("Basic.Stats.Status.Inactive"));
if (isActive) if (isActive) {
setClasses(active, "text-danger"); setClasses(active, "text-danger");
}
active->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); active->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
volume->setMinimum(MIN_DB - 0.1); volume->setMinimum(MIN_DB - 0.1);
@@ -132,10 +135,11 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) : source(
const char *speakers = config_get_string(main->Config(), "Audio", "ChannelSetup"); const char *speakers = config_get_string(main->Config(), "Audio", "ChannelSetup");
if (strcmp(speakers, "Mono") == 0) if (strcmp(speakers, "Mono") == 0) {
balance->setEnabled(false); balance->setEnabled(false);
else } else {
balance->setEnabled(true); balance->setEnabled(true);
}
float bal = obs_source_get_balance_value(source) * 100.0f; float bal = obs_source_get_balance_value(source) * 100.0f;
balance->setValue((int)bal); balance->setValue((int)bal);
@@ -187,8 +191,9 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) : source(
speaker_layout sl = obs_source_get_speaker_layout(source); speaker_layout sl = obs_source_get_speaker_layout(source);
if (sl != SPEAKERS_STEREO) if (sl != SPEAKERS_STEREO) {
balanceContainer->setEnabled(false); balanceContainer->setEnabled(false);
}
mixerContainer->layout()->addWidget(mixer1); mixerContainer->layout()->addWidget(mixer1);
mixerContainer->layout()->addWidget(mixer2); mixerContainer->layout()->addWidget(mixer2);
@@ -204,8 +209,9 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_) : source(
connect(balance, &BalanceSlider::valueChanged, this, &OBSAdvAudioCtrl::balanceChanged); connect(balance, &BalanceSlider::valueChanged, this, &OBSAdvAudioCtrl::balanceChanged);
connect(balance, &BalanceSlider::doubleClicked, this, &OBSAdvAudioCtrl::ResetBalance); connect(balance, &BalanceSlider::doubleClicked, this, &OBSAdvAudioCtrl::ResetBalance);
connect(syncOffset, &QSpinBox::valueChanged, this, &OBSAdvAudioCtrl::syncOffsetChanged); connect(syncOffset, &QSpinBox::valueChanged, this, &OBSAdvAudioCtrl::syncOffsetChanged);
if (obs_audio_monitoring_available()) if (obs_audio_monitoring_available()) {
connect(monitoringType, &QComboBox::currentIndexChanged, this, &OBSAdvAudioCtrl::monitoringTypeChanged); connect(monitoringType, &QComboBox::currentIndexChanged, this, &OBSAdvAudioCtrl::monitoringTypeChanged);
}
auto connectMixer = [this](QCheckBox *mixer, int num) { auto connectMixer = [this](QCheckBox *mixer, int num) {
connect(mixer, &QCheckBox::clicked, this, connect(mixer, &QCheckBox::clicked, this,
@@ -230,8 +236,9 @@ OBSAdvAudioCtrl::~OBSAdvAudioCtrl()
forceMono->deleteLater(); forceMono->deleteLater();
balanceContainer->deleteLater(); balanceContainer->deleteLater();
syncOffset->deleteLater(); syncOffset->deleteLater();
if (obs_audio_monitoring_available()) if (obs_audio_monitoring_available()) {
monitoringType->deleteLater(); monitoringType->deleteLater();
}
mixerContainer->deleteLater(); mixerContainer->deleteLater();
} }
@@ -247,8 +254,9 @@ void OBSAdvAudioCtrl::ShowAudioControl(QGridLayout *layout)
layout->addWidget(forceMono, lastRow, idx++); layout->addWidget(forceMono, lastRow, idx++);
layout->addWidget(balanceContainer, lastRow, idx++); layout->addWidget(balanceContainer, lastRow, idx++);
layout->addWidget(syncOffset, lastRow, idx++); layout->addWidget(syncOffset, lastRow, idx++);
if (obs_audio_monitoring_available()) if (obs_audio_monitoring_available()) {
layout->addWidget(monitoringType, lastRow, idx++); layout->addWidget(monitoringType, lastRow, idx++);
}
layout->addWidget(mixerContainer, lastRow, idx++); layout->addWidget(mixerContainer, lastRow, idx++);
layout->layout()->setAlignment(mixerContainer, Qt::AlignVCenter); layout->layout()->setAlignment(mixerContainer, Qt::AlignVCenter);
layout->setHorizontalSpacing(15); layout->setHorizontalSpacing(15);
@@ -431,10 +439,11 @@ void OBSAdvAudioCtrl::percentChanged(int percent)
static inline void set_mono(obs_source_t *source, bool mono) static inline void set_mono(obs_source_t *source, bool mono)
{ {
uint32_t flags = obs_source_get_flags(source); uint32_t flags = obs_source_get_flags(source);
if (mono) if (mono) {
flags |= OBS_SOURCE_FLAG_FORCE_MONO; flags |= OBS_SOURCE_FLAG_FORCE_MONO;
else } else {
flags &= ~OBS_SOURCE_FLAG_FORCE_MONO; flags &= ~OBS_SOURCE_FLAG_FORCE_MONO;
}
obs_source_set_flags(source, flags); obs_source_set_flags(source, flags);
} }
@@ -443,13 +452,15 @@ void OBSAdvAudioCtrl::downmixMonoChanged(bool val)
uint32_t flags = obs_source_get_flags(source); uint32_t flags = obs_source_get_flags(source);
bool forceMonoActive = (flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0; bool forceMonoActive = (flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0;
if (forceMonoActive == val) if (forceMonoActive == val) {
return; return;
}
if (val) if (val) {
flags |= OBS_SOURCE_FLAG_FORCE_MONO; flags |= OBS_SOURCE_FLAG_FORCE_MONO;
else } else {
flags &= ~OBS_SOURCE_FLAG_FORCE_MONO; flags &= ~OBS_SOURCE_FLAG_FORCE_MONO;
}
obs_source_set_flags(source, flags); obs_source_set_flags(source, flags);
@@ -502,8 +513,9 @@ void OBSAdvAudioCtrl::syncOffsetChanged(int milliseconds)
int64_t prev = obs_source_get_sync_offset(source); int64_t prev = obs_source_get_sync_offset(source);
int64_t val = int64_t(milliseconds) * NSEC_PER_MSEC; int64_t val = int64_t(milliseconds) * NSEC_PER_MSEC;
if (prev / NSEC_PER_MSEC == milliseconds) if (prev / NSEC_PER_MSEC == milliseconds) {
return; return;
}
obs_source_set_sync_offset(source, val); obs_source_set_sync_offset(source, val);
@@ -559,10 +571,11 @@ static inline void setMixer(obs_source_t *source, const int mixerIdx, const bool
uint32_t mixers = obs_source_get_audio_mixers(source); uint32_t mixers = obs_source_get_audio_mixers(source);
uint32_t new_mixers = mixers; uint32_t new_mixers = mixers;
if (checked) if (checked) {
new_mixers |= (1 << mixerIdx); new_mixers |= (1 << mixerIdx);
else } else {
new_mixers &= ~(1 << mixerIdx); new_mixers &= ~(1 << mixerIdx);
}
obs_source_set_audio_mixers(source, new_mixers); obs_source_set_audio_mixers(source, new_mixers);
@@ -23,8 +23,9 @@
void OBSPreviewScalingComboBox::PreviewFixedScalingChanged(bool fixed) void OBSPreviewScalingComboBox::PreviewFixedScalingChanged(bool fixed)
{ {
if (fixedScaling == fixed) if (fixedScaling == fixed) {
return; return;
}
fixedScaling = fixed; fixedScaling = fixed;
UpdateSelection(); UpdateSelection();
@@ -60,8 +61,9 @@ void OBSPreviewScalingComboBox::PreviewScaleChanged(float scale)
void OBSPreviewScalingComboBox::SetScaleOutputEnabled(bool show) void OBSPreviewScalingComboBox::SetScaleOutputEnabled(bool show)
{ {
if (scaleOutputEnabled == show) if (scaleOutputEnabled == show) {
return; return;
}
scaleOutputEnabled = show; scaleOutputEnabled = show;
+6 -3
View File
@@ -175,8 +175,9 @@ void SceneTree::RepositionGrid(QDragMoveEvent *event)
for (int i = 0; i < count(); i++) { for (int i = 0; i < count(); i++) {
auto *wItem = item(i); auto *wItem = item(i);
if (wItem->isSelected()) if (wItem->isSelected()) {
continue; continue;
}
QModelIndex index = indexFromItem(wItem); QModelIndex index = indexFromItem(wItem);
@@ -193,8 +194,9 @@ void SceneTree::RepositionGrid(QDragMoveEvent *event)
for (int i = 0; i < count(); i++) { for (int i = 0; i < count(); i++) {
auto *wItem = item(i); auto *wItem = item(i);
if (wItem->isSelected()) if (wItem->isSelected()) {
continue; continue;
}
QModelIndex index = indexFromItem(wItem); QModelIndex index = indexFromItem(wItem);
@@ -238,7 +240,8 @@ void SceneTree::rowsInserted(const QModelIndex &parent, int start, int end)
// Workaround for QTBUG-105870. Remove once that is solved upstream. // Workaround for QTBUG-105870. Remove once that is solved upstream.
void SceneTree::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) void SceneTree::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{ {
if (selected.count() == 0 && deselected.count() > 0 && !property("clearing").toBool()) if (selected.count() == 0 && deselected.count() > 0 && !property("clearing").toBool()) {
setCurrentRow(deselected.indexes().front().row()); setCurrentRow(deselected.indexes().front().row());
} }
}
#endif #endif
+4 -2
View File
@@ -30,8 +30,9 @@ void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable)
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
OBSSource currentSceneSource = main->GetCurrentSceneSource(); OBSSource currentSceneSource = main->GetCurrentSceneSource();
if (!currentSceneSource) if (!currentSceneSource) {
return; return;
}
std::string scene_uuid = obs_source_get_uuid(currentSceneSource); std::string scene_uuid = obs_source_get_uuid(currentSceneSource);
auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) { auto undo_redo = [scene_uuid = std::move(scene_uuid), main](const std::string &data) {
OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str()); OBSDataAutoRelease settings = obs_data_create_from_json(data.c_str());
@@ -52,9 +53,10 @@ void SourceToolbar::SetUndoProperties(obs_source_t *source, bool repeatable)
std::string undo_data(obs_data_get_json(oldData)); std::string undo_data(obs_data_get_json(oldData));
std::string redo_data(obs_data_get_json(new_settings)); std::string redo_data(obs_data_get_json(new_settings));
if (undo_data.compare(redo_data) != 0) if (undo_data.compare(redo_data) != 0) {
main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo, main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, undo_redo,
undo_data, redo_data, repeatable); undo_data, redo_data, repeatable);
}
oldData = nullptr; oldData = nullptr;
} }
+30 -16
View File
@@ -95,23 +95,27 @@ void SourceTree::SelectItem(obs_sceneitem_t *sceneitem, bool select)
int i = 0; int i = 0;
for (; i < stm->items.count(); i++) { for (; i < stm->items.count(); i++) {
if (stm->items[i] == sceneitem) if (stm->items[i] == sceneitem) {
break; break;
} }
}
if (i == stm->items.count()) if (i == stm->items.count()) {
return; return;
}
QModelIndex index = stm->createIndex(i, 0); QModelIndex index = stm->createIndex(i, 0);
if (index.isValid() && select != selectionModel()->isSelected(index)) if (index.isValid() && select != selectionModel()->isSelected(index)) {
selectionModel()->select(index, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); selectionModel()->select(index, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
} }
}
void SourceTree::mouseDoubleClickEvent(QMouseEvent *event) void SourceTree::mouseDoubleClickEvent(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) if (event->button() == Qt::LeftButton) {
QListView::mouseDoubleClickEvent(event); QListView::mouseDoubleClickEvent(event);
} }
}
void SourceTree::dropEvent(QDropEvent *event) void SourceTree::dropEvent(QDropEvent *event)
{ {
@@ -152,10 +156,12 @@ void SourceTree::dropEvent(QDropEvent *event)
obs_sceneitem_t *dropGroup = itemIsGroup ? dropItem : obs_sceneitem_get_group(scene, dropItem); obs_sceneitem_t *dropGroup = itemIsGroup ? dropItem : obs_sceneitem_get_group(scene, dropItem);
/* not a group if moving above the group */ /* not a group if moving above the group */
if (indicator == QAbstractItemView::AboveItem && itemIsGroup) if (indicator == QAbstractItemView::AboveItem && itemIsGroup) {
dropGroup = nullptr; dropGroup = nullptr;
if (emptyDrop) }
if (emptyDrop) {
dropGroup = nullptr; dropGroup = nullptr;
}
/* --------------------------------------- */ /* --------------------------------------- */
/* remember to remove list items if */ /* remember to remove list items if */
@@ -169,8 +175,9 @@ void SourceTree::dropEvent(QDropEvent *event)
} }
if (indicator == QAbstractItemView::BelowItem || indicator == QAbstractItemView::OnItem || if (indicator == QAbstractItemView::BelowItem || indicator == QAbstractItemView::OnItem ||
indicator == QAbstractItemView::OnViewport) indicator == QAbstractItemView::OnViewport) {
row++; row++;
}
if (row < 0 || row > stm->items.count()) { if (row < 0 || row > stm->items.count()) {
QListView::dropEvent(event); QListView::dropEvent(event);
@@ -194,10 +201,11 @@ void SourceTree::dropEvent(QDropEvent *event)
/* below another group */ /* below another group */
obs_sceneitem_t *itemBelow; obs_sceneitem_t *itemBelow;
if (row == stm->items.count()) if (row == stm->items.count()) {
itemBelow = nullptr; itemBelow = nullptr;
else } else {
itemBelow = stm->items[row]; itemBelow = stm->items[row];
}
if (hasGroups) { if (hasGroups) {
if (!itemBelow || obs_sceneitem_get_group(scene, itemBelow) != dropGroup) { if (!itemBelow || obs_sceneitem_get_group(scene, itemBelow) != dropGroup) {
@@ -220,11 +228,13 @@ void SourceTree::dropEvent(QDropEvent *event)
std::vector<obs_source_t *> sources; std::vector<obs_source_t *> sources;
for (int i = 0; i < indices.size(); i++) { for (int i = 0; i < indices.size(); i++) {
obs_sceneitem_t *item = items[indices[i].row()]; obs_sceneitem_t *item = items[indices[i].row()];
if (obs_sceneitem_get_scene(item) != scene) if (obs_sceneitem_get_scene(item) != scene) {
sources.push_back(obs_scene_get_source(obs_sceneitem_get_scene(item))); sources.push_back(obs_scene_get_source(obs_sceneitem_get_scene(item)));
} }
if (dropGroup) }
if (dropGroup) {
sources.push_back(obs_sceneitem_get_source(dropGroup)); sources.push_back(obs_sceneitem_get_source(dropGroup));
}
OBSData undo_data = main->BackupScene(scene, &sources); OBSData undo_data = main->BackupScene(scene, &sources);
/* --------------------------------------- */ /* --------------------------------------- */
@@ -266,8 +276,9 @@ void SourceTree::dropEvent(QDropEvent *event)
QList<QPersistentModelIndex> persistentIndices; QList<QPersistentModelIndex> persistentIndices;
persistentIndices.reserve(indices.count()); persistentIndices.reserve(indices.count());
for (QModelIndex &index : indices) for (QModelIndex &index : indices) {
persistentIndices.append(index); persistentIndices.append(index);
}
std::sort(persistentIndices.begin(), persistentIndices.end()); std::sort(persistentIndices.begin(), persistentIndices.end());
/* --------------------------------------- */ /* --------------------------------------- */
@@ -279,8 +290,9 @@ void SourceTree::dropEvent(QDropEvent *event)
int to = r; int to = r;
int itemTo = to; int itemTo = to;
if (itemTo > from) if (itemTo > from) {
itemTo--; itemTo--;
}
if (itemTo != from) { if (itemTo != from) {
stm->beginMoveRows(QModelIndex(), from, from, QModelIndex(), to); stm->beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
@@ -347,10 +359,11 @@ void SourceTree::dropEvent(QDropEvent *event)
continue; continue;
} }
if (!hasGroups && i >= firstIdx && i <= lastIdx) if (!hasGroups && i >= firstIdx && i <= lastIdx) {
group = dropGroup; group = dropGroup;
else } else {
group = obs_sceneitem_get_group(scene, item); group = obs_sceneitem_get_group(scene, item);
}
if (lastGroup && lastGroup != group) { if (lastGroup && lastGroup != group) {
insertLastGroup(); insertLastGroup();
@@ -481,8 +494,9 @@ void SourceTree::NewGroupEdit(int row)
bool SourceTree::Edit(int row) bool SourceTree::Edit(int row)
{ {
SourceTreeModel *stm = GetStm(); SourceTreeModel *stm = GetStm();
if (row < 0 || row >= stm->items.count()) if (row < 0 || row >= stm->items.count()) {
return false; return false;
}
QModelIndex index = stm->createIndex(row, 0); QModelIndex index = stm->createIndex(row, 0);
QWidget *widget = indexWidget(index); QWidget *widget = indexWidget(index);
+2 -1
View File
@@ -9,8 +9,9 @@ QSize SourceTreeDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo
SourceTree *tree = qobject_cast<SourceTree *>(parent()); SourceTree *tree = qobject_cast<SourceTree *>(parent());
QWidget *item = tree->indexWidget(index); QWidget *item = tree->indexWidget(index);
if (!item) if (!item) {
return QStyledItemDelegate::sizeHint(option, index); return QStyledItemDelegate::sizeHint(option, index);
}
return (QSize(item->sizeHint())); return (QSize(item->sizeHint()));
} }
+27 -15
View File
@@ -55,12 +55,13 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) : tre
if (tree->iconsVisible) { if (tree->iconsVisible) {
QIcon icon; QIcon icon;
if (strcmp(id, "scene") == 0) if (strcmp(id, "scene") == 0) {
icon = main->GetSceneIcon(); icon = main->GetSceneIcon();
else if (strcmp(id, "group") == 0) } else if (strcmp(id, "group") == 0) {
icon = main->GetGroupIcon(); icon = main->GetGroupIcon();
else } else {
icon = main->GetSourceIcon(id); icon = main->GetSourceIcon(id);
}
QPixmap pixmap = icon.pixmap(QSize(16, 16)); QPixmap pixmap = icon.pixmap(QSize(16, 16));
@@ -136,8 +137,9 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) : tre
OBSSourceAutoRelease s = obs_get_source_by_uuid(uuid.c_str()); OBSSourceAutoRelease s = obs_get_source_by_uuid(uuid.c_str());
obs_scene_t *sc = obs_group_or_scene_from_source(s); obs_scene_t *sc = obs_group_or_scene_from_source(s);
obs_sceneitem_t *si = obs_scene_find_sceneitem_by_id(sc, id); obs_sceneitem_t *si = obs_scene_find_sceneitem_by_id(sc, id);
if (si) if (si) {
obs_sceneitem_set_visible(si, val); obs_sceneitem_set_visible(si, val);
}
}; };
QString str = QTStr(val ? "Undo.ShowSceneItem" : "Undo.HideSceneItem"); QString str = QTStr(val ? "Undo.ShowSceneItem" : "Undo.HideSceneItem");
@@ -183,8 +185,9 @@ void SourceTreeItem::Clear()
void SourceTreeItem::ReconnectSignals() void SourceTreeItem::ReconnectSignals()
{ {
if (!sceneitem) if (!sceneitem) {
return; return;
}
DisconnectSignals(); DisconnectSignals();
@@ -200,8 +203,9 @@ void SourceTreeItem::ReconnectSignals()
Q_ARG(OBSScene, curScene)); Q_ARG(OBSScene, curScene));
curItem = nullptr; curItem = nullptr;
} }
if (!curItem) if (!curItem) {
QMetaObject::invokeMethod(this_, "Clear"); QMetaObject::invokeMethod(this_, "Clear");
}
}; };
auto itemVisible = [](void *data, calldata_t *cd) { auto itemVisible = [](void *data, calldata_t *cd) {
@@ -209,8 +213,9 @@ void SourceTreeItem::ReconnectSignals()
obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item");
bool visible = calldata_bool(cd, "visible"); bool visible = calldata_bool(cd, "visible");
if (curItem == this_->sceneitem) if (curItem == this_->sceneitem) {
QMetaObject::invokeMethod(this_, "VisibilityChanged", Q_ARG(bool, visible)); QMetaObject::invokeMethod(this_, "VisibilityChanged", Q_ARG(bool, visible));
}
}; };
auto itemLocked = [](void *data, calldata_t *cd) { auto itemLocked = [](void *data, calldata_t *cd) {
@@ -218,24 +223,27 @@ void SourceTreeItem::ReconnectSignals()
obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item");
bool locked = calldata_bool(cd, "locked"); bool locked = calldata_bool(cd, "locked");
if (curItem == this_->sceneitem) if (curItem == this_->sceneitem) {
QMetaObject::invokeMethod(this_, "LockedChanged", Q_ARG(bool, locked)); QMetaObject::invokeMethod(this_, "LockedChanged", Q_ARG(bool, locked));
}
}; };
auto itemSelect = [](void *data, calldata_t *cd) { auto itemSelect = [](void *data, calldata_t *cd) {
SourceTreeItem *this_ = static_cast<SourceTreeItem *>(data); SourceTreeItem *this_ = static_cast<SourceTreeItem *>(data);
obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item");
if (curItem == this_->sceneitem) if (curItem == this_->sceneitem) {
QMetaObject::invokeMethod(this_, "Select"); QMetaObject::invokeMethod(this_, "Select");
}
}; };
auto itemDeselect = [](void *data, calldata_t *cd) { auto itemDeselect = [](void *data, calldata_t *cd) {
SourceTreeItem *this_ = static_cast<SourceTreeItem *>(data); SourceTreeItem *this_ = static_cast<SourceTreeItem *>(data);
obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item"); obs_sceneitem_t *curItem = (obs_sceneitem_t *)calldata_ptr(cd, "item");
if (curItem == this_->sceneitem) if (curItem == this_->sceneitem) {
QMetaObject::invokeMethod(this_, "Deselect"); QMetaObject::invokeMethod(this_, "Deselect");
}
}; };
auto reorderGroup = [](void *data, calldata_t *) { auto reorderGroup = [](void *data, calldata_t *) {
@@ -384,8 +392,9 @@ void SourceTreeItem::ExitEditModeInternal(bool save)
/* ----------------------------------------- */ /* ----------------------------------------- */
/* check for empty string */ /* check for empty string */
if (!save) if (!save) {
return; return;
}
if (newName.empty()) { if (newName.empty()) {
OBSMessageBox::information(main, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text")); OBSMessageBox::information(main, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text"));
@@ -396,8 +405,9 @@ void SourceTreeItem::ExitEditModeInternal(bool save)
/* Check for same name */ /* Check for same name */
obs_source_t *source = obs_sceneitem_get_source(sceneitem); obs_source_t *source = obs_sceneitem_get_source(sceneitem);
if (newName == obs_source_get_name(source)) if (newName == obs_source_get_name(source)) {
return; return;
}
/* ----------------------------------------- */ /* ----------------------------------------- */
/* check for existing source */ /* check for existing source */
@@ -442,8 +452,9 @@ void SourceTreeItem::ExitEditModeInternal(bool save)
bool SourceTreeItem::eventFilter(QObject *object, QEvent *event) bool SourceTreeItem::eventFilter(QObject *object, QEvent *event)
{ {
if (editor != object) if (editor != object) {
return false; return false;
}
if (LineEditCanceled(event)) { if (LineEditCanceled(event)) {
QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, false)); QMetaObject::invokeMethod(this, "ExitEditMode", Qt::QueuedConnection, Q_ARG(bool, false));
@@ -554,11 +565,12 @@ void SourceTreeItem::ExpandClicked(bool checked)
obs_data_set_bool(data, "collapsed", checked); obs_data_set_bool(data, "collapsed", checked);
if (!checked) if (!checked) {
tree->GetStm()->ExpandGroup(sceneitem); tree->GetStm()->ExpandGroup(sceneitem);
else } else {
tree->GetStm()->CollapseGroup(sceneitem); tree->GetStm()->CollapseGroup(sceneitem);
} }
}
void SourceTreeItem::Select() void SourceTreeItem::Select()
{ {
+33 -17
View File
@@ -163,8 +163,9 @@ void SourceTreeModel::ReorderItems()
beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1, QModelIndex(), idx1New + count); beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1, QModelIndex(), idx1New + count);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
int to = idx1New + count; int to = idx1New + count;
if (to > idx1Old) if (to > idx1Old) {
to--; to--;
}
MoveItem(items, idx1Old, to); MoveItem(items, idx1Old, to);
} }
endMoveRows(); endMoveRows();
@@ -194,8 +195,9 @@ void SourceTreeModel::Remove(obs_sceneitem_t *item)
} }
} }
if (idx == -1) if (idx == -1) {
return; return;
}
int startIdx = idx; int startIdx = idx;
int endIdx = idx; int endIdx = idx;
@@ -208,27 +210,30 @@ void SourceTreeModel::Remove(obs_sceneitem_t *item)
obs_sceneitem_t *subitem = items[i]; obs_sceneitem_t *subitem = items[i];
obs_scene_t *subscene = obs_sceneitem_get_scene(subitem); obs_scene_t *subscene = obs_sceneitem_get_scene(subitem);
if (subscene == scene) if (subscene == scene) {
endIdx = i; endIdx = i;
else } else {
break; break;
} }
} }
}
beginRemoveRows(QModelIndex(), startIdx, endIdx); beginRemoveRows(QModelIndex(), startIdx, endIdx);
items.remove(idx, endIdx - startIdx + 1); items.remove(idx, endIdx - startIdx + 1);
endRemoveRows(); endRemoveRows();
if (is_group) if (is_group) {
UpdateGroupState(true); UpdateGroupState(true);
}
OBSBasic::Get()->UpdateContextBarDeferred(); OBSBasic::Get()->UpdateContextBarDeferred();
} }
OBSSceneItem SourceTreeModel::Get(int idx) OBSSceneItem SourceTreeModel::Get(int idx)
{ {
if (idx == -1 || idx >= items.count()) if (idx == -1 || idx >= items.count()) {
return OBSSceneItem(); return OBSSceneItem();
}
return items[idx]; return items[idx];
} }
@@ -255,8 +260,9 @@ QVariant SourceTreeModel::data(const QModelIndex &index, int role) const
Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const
{ {
if (!index.isValid()) if (!index.isValid()) {
return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled; return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled;
}
obs_sceneitem_t *item = items[index.row()]; obs_sceneitem_t *item = items[index.row()];
bool is_group = obs_sceneitem_is_group(item); bool is_group = obs_sceneitem_is_group(item);
@@ -278,8 +284,9 @@ QString SourceTreeModel::GetNewGroupName()
int i = 2; int i = 2;
for (;;) { for (;;) {
OBSSourceAutoRelease group = obs_get_source_by_name(QT_TO_UTF8(name)); OBSSourceAutoRelease group = obs_get_source_by_name(QT_TO_UTF8(name));
if (!group) if (!group) {
break; break;
}
name = QTStr("Basic.Main.Group").arg(QString::number(i++)); name = QTStr("Basic.Main.Group").arg(QString::number(i++));
} }
@@ -290,8 +297,9 @@ void SourceTreeModel::AddGroup()
{ {
QString name = GetNewGroupName(); QString name = GetNewGroupName();
obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name)); obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name));
if (!group) if (!group) {
return; return;
}
beginInsertRows(QModelIndex(), 0, 0); beginInsertRows(QModelIndex(), 0, 0);
items.insert(0, group); items.insert(0, group);
@@ -305,8 +313,9 @@ void SourceTreeModel::AddGroup()
void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices) void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
{ {
if (indices.count() == 0) if (indices.count() == 0) {
return; return;
}
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
OBSScene scene = GetCurrentScene(); OBSScene scene = GetCurrentScene();
@@ -329,8 +338,9 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
main->undo_s.push_disabled(); main->undo_s.push_disabled();
for (obs_sceneitem_t *item : item_order) for (obs_sceneitem_t *item : item_order) {
obs_sceneitem_select(item, false); obs_sceneitem_select(item, false);
}
hasGroups = true; hasGroups = true;
st->UpdateWidgets(true); st->UpdateWidgets(true);
@@ -349,8 +359,9 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices) void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
{ {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
if (indices.count() == 0) if (indices.count() == 0) {
return; return;
}
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
OBSData undoData = main->BackupScene(scene); OBSData undoData = main->BackupScene(scene);
@@ -369,8 +380,9 @@ void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
void SourceTreeModel::ExpandGroup(obs_sceneitem_t *item) void SourceTreeModel::ExpandGroup(obs_sceneitem_t *item)
{ {
int itemIdx = items.indexOf(item); int itemIdx = items.indexOf(item);
if (itemIdx == -1) if (itemIdx == -1) {
return; return;
}
itemIdx++; itemIdx++;
@@ -379,12 +391,14 @@ void SourceTreeModel::ExpandGroup(obs_sceneitem_t *item)
QVector<OBSSceneItem> subItems; QVector<OBSSceneItem> subItems;
obs_scene_enum_items(scene, enumItem, &subItems); obs_scene_enum_items(scene, enumItem, &subItems);
if (!subItems.size()) if (!subItems.size()) {
return; return;
}
beginInsertRows(QModelIndex(), itemIdx, itemIdx + subItems.size() - 1); beginInsertRows(QModelIndex(), itemIdx, itemIdx + subItems.size() - 1);
for (int i = 0; i < subItems.size(); i++) for (int i = 0; i < subItems.size(); i++) {
items.insert(i + itemIdx, subItems[i]); items.insert(i + itemIdx, subItems[i]);
}
endInsertRows(); endInsertRows();
st->UpdateWidgets(); st->UpdateWidgets();
@@ -401,14 +415,16 @@ void SourceTreeModel::CollapseGroup(obs_sceneitem_t *item)
obs_scene_t *itemScene = obs_sceneitem_get_scene(items[i]); obs_scene_t *itemScene = obs_sceneitem_get_scene(items[i]);
if (itemScene == scene) { if (itemScene == scene) {
if (startIdx == -1) if (startIdx == -1) {
startIdx = i; startIdx = i;
}
endIdx = i; endIdx = i;
} }
} }
if (startIdx == -1) if (startIdx == -1) {
return; return;
}
beginRemoveRows(QModelIndex(), startIdx, endIdx); beginRemoveRows(QModelIndex(), startIdx, endIdx);
items.remove(startIdx, endIdx - startIdx + 1); items.remove(startIdx, endIdx - startIdx + 1);
+2 -1
View File
@@ -40,9 +40,10 @@ TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source)
bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr)); bool single_line = !read_from_file && (!text || (strchr(text, '\n') == nullptr));
ui->emptySpace->setVisible(!single_line); ui->emptySpace->setVisible(!single_line);
ui->text->setVisible(single_line); ui->text->setVisible(single_line);
if (single_line) if (single_line) {
ui->text->setText(text); ui->text->setText(text);
} }
}
TextSourceToolbar::~TextSourceToolbar() {} TextSourceToolbar::~TextSourceToolbar() {}
+17 -9
View File
@@ -11,12 +11,14 @@ static int CountVideoSources()
{ {
int count = 0; int count = 0;
auto countSources = [](void *param, obs_source_t *source) { auto countSources = [](void *param, obs_source_t *source) {
if (!source) if (!source) {
return true; return true;
}
uint32_t flags = obs_source_get_output_flags(source); uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_VIDEO) != 0) if ((flags & OBS_SOURCE_VIDEO) != 0) {
(*static_cast<int *>(param))++; (*static_cast<int *>(param))++;
}
return true; return true;
}; };
@@ -28,12 +30,14 @@ static int CountVideoSources()
bool UIValidation::NoSourcesConfirmation(QWidget *parent) bool UIValidation::NoSourcesConfirmation(QWidget *parent)
{ {
// There are sources, don't need confirmation // There are sources, don't need confirmation
if (CountVideoSources() != 0) if (CountVideoSources() != 0) {
return true; return true;
}
// Ignore no video if no parent is visible to alert on // Ignore no video if no parent is visible to alert on
if (!parent->isVisible()) if (!parent->isVisible()) {
return true; return true;
}
QString msg = QTStr("NoSources.Text"); QString msg = QTStr("NoSources.Text");
msg += "\n\n"; msg += "\n\n";
@@ -48,16 +52,18 @@ bool UIValidation::NoSourcesConfirmation(QWidget *parent)
messageBox.setIcon(QMessageBox::Question); messageBox.setIcon(QMessageBox::Question);
messageBox.exec(); messageBox.exec();
if (messageBox.clickedButton() != yesButton) if (messageBox.clickedButton() != yesButton) {
return false; return false;
else } else {
return true; return true;
} }
}
StreamSettingsAction UIValidation::StreamSettingsConfirmation(QWidget *parent, OBSService service) StreamSettingsAction UIValidation::StreamSettingsConfirmation(QWidget *parent, OBSService service)
{ {
if (obs_service_can_try_to_connect(service)) if (obs_service_can_try_to_connect(service)) {
return StreamSettingsAction::ContinueStream; return StreamSettingsAction::ContinueStream;
}
char const *serviceType = obs_service_get_type(service); char const *serviceType = obs_service_get_type(service);
bool isCustomService = (strcmp(serviceType, "rtmp_custom") == 0); bool isCustomService = (strcmp(serviceType, "rtmp_custom") == 0);
@@ -100,10 +106,12 @@ StreamSettingsAction UIValidation::StreamSettingsConfirmation(QWidget *parent, O
messageBox.setIcon(QMessageBox::Warning); messageBox.setIcon(QMessageBox::Warning);
messageBox.exec(); messageBox.exec();
if (messageBox.clickedButton() == settings) if (messageBox.clickedButton() == settings) {
return StreamSettingsAction::OpenSettings; return StreamSettingsAction::OpenSettings;
if (messageBox.clickedButton() == cancel) }
if (messageBox.clickedButton() == cancel) {
return StreamSettingsAction::Cancel; return StreamSettingsAction::Cancel;
}
return StreamSettingsAction::ContinueStream; return StreamSettingsAction::ContinueStream;
} }
+2 -1
View File
@@ -19,8 +19,9 @@ void UrlPushButton::mousePressEvent(QMouseEvent *event)
{ {
Q_UNUSED(event) Q_UNUSED(event)
QUrl openUrl = m_targetUrl; QUrl openUrl = m_targetUrl;
if (openUrl.isEmpty()) if (openUrl.isEmpty()) {
return; return;
}
QDesktopServices::openUrl(openUrl); QDesktopServices::openUrl(openUrl);
} }
@@ -14,13 +14,15 @@ void VisibilityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
QObject *parentObj = parent(); QObject *parentObj = parent();
QListWidget *list = qobject_cast<QListWidget *>(parentObj); QListWidget *list = qobject_cast<QListWidget *>(parentObj);
if (!list) if (!list) {
return; return;
}
QListWidgetItem *item = list->item(index.row()); QListWidgetItem *item = list->item(index.row());
VisibilityItemWidget *widget = qobject_cast<VisibilityItemWidget *>(list->itemWidget(item)); VisibilityItemWidget *widget = qobject_cast<VisibilityItemWidget *>(list->itemWidget(item));
if (!widget) if (!widget) {
return; return;
}
bool selected = option.state.testFlag(QStyle::State_Selected); bool selected = option.state.testFlag(QStyle::State_Selected);
bool active = option.state.testFlag(QStyle::State_Active); bool active = option.state.testFlag(QStyle::State_Active);
@@ -40,10 +42,11 @@ void VisibilityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
QPalette::ColorRole role; QPalette::ColorRole role;
if (selected && active) if (selected && active) {
role = highlightRole; role = highlightRole;
else } else {
role = QPalette::WindowText; role = QPalette::WindowText;
}
widget->SetColor(palette.color(group, role), active, selected); widget->SetColor(palette.color(group, role), active, selected);
} }
@@ -51,8 +54,9 @@ void VisibilityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
bool VisibilityItemDelegate::eventFilter(QObject *object, QEvent *event) bool VisibilityItemDelegate::eventFilter(QObject *object, QEvent *event)
{ {
QWidget *editor = qobject_cast<QWidget *>(object); QWidget *editor = qobject_cast<QWidget *>(object);
if (!editor) if (!editor) {
return false; return false;
}
if (event->type() == QEvent::KeyPress) { if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+4 -2
View File
@@ -41,15 +41,17 @@ void VisibilityItemWidget::OBSSourceEnabled(void *param, calldata_t *data)
void VisibilityItemWidget::SourceEnabled(bool enabled) void VisibilityItemWidget::SourceEnabled(bool enabled)
{ {
if (vis->isChecked() != enabled) if (vis->isChecked() != enabled) {
vis->setChecked(enabled); vis->setChecked(enabled);
} }
}
void VisibilityItemWidget::SetColor(const QColor &color, bool active_, bool selected_) void VisibilityItemWidget::SetColor(const QColor &color, bool active_, bool selected_)
{ {
/* Do not update unless the state has actually changed */ /* Do not update unless the state has actually changed */
if (active_ == active && selected_ == selected) if (active_ == active && selected_ == selected) {
return; return;
}
QPalette pal = vis->palette(); QPalette pal = vis->palette();
pal.setColor(QPalette::WindowText, color); pal.setColor(QPalette::WindowText, color);
@@ -27,10 +27,11 @@ QVariant VolumeAccessibleInterface::currentValue() const
QString text; QString text;
float db = obs_fader_get_db(slider()->fad); float db = obs_fader_get_db(slider()->fad);
if (db < -96.0f) if (db < -96.0f) {
text = "-inf dB"; text = "-inf dB";
else } else {
text = QString::number(db, 'f', 1).append(" dB"); text = QString::number(db, 'f', 1).append(" dB");
}
return text; return text;
} }
+2 -1
View File
@@ -21,8 +21,9 @@ void WindowCaptureToolbar::Init()
ui->activateButton = nullptr; ui->activateButton = nullptr;
obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture"); obs_module_t *mod = get_os_module("win-capture", "mac-capture", "linux-capture");
if (!mod) if (!mod) {
return; return;
}
const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window"); const char *device_str = get_os_text(mod, "WindowCapture.Window", "WindowUtils.Window", "Window");
ui->deviceLabel->setText(device_str); ui->deviceLabel->setText(device_str);
+6 -3
View File
@@ -68,17 +68,20 @@ static bool IsWhitespace(char ch)
static void CleanWhitespace(std::string &str) static void CleanWhitespace(std::string &str)
{ {
while (str.size() && IsWhitespace(str.back())) while (str.size() && IsWhitespace(str.back())) {
str.erase(str.end() - 1); str.erase(str.end() - 1);
while (str.size() && IsWhitespace(str.front())) }
while (str.size() && IsWhitespace(str.front())) {
str.erase(str.begin()); str.erase(str.begin());
} }
}
bool NameDialog::AskForName(QWidget *parent, const QString &title, const QString &text, std::string &userTextInput, bool NameDialog::AskForName(QWidget *parent, const QString &title, const QString &text, std::string &userTextInput,
const QString &placeHolder, int maxSize) const QString &placeHolder, int maxSize)
{ {
if (maxSize <= 0 || maxSize > 32767) if (maxSize <= 0 || maxSize > 32767) {
maxSize = 170; maxSize = 170;
}
NameDialog dialog(parent); NameDialog dialog(parent);
dialog.setWindowTitle(title); dialog.setWindowTitle(title);
+7 -4
View File
@@ -92,19 +92,22 @@ void OAuthLogin::urlChanged(const QString &url)
{ {
std::string uri = get_token ? "access_token=" : "code="; std::string uri = get_token ? "access_token=" : "code=";
int code_idx = url.indexOf(uri.c_str()); int code_idx = url.indexOf(uri.c_str());
if (code_idx == -1) if (code_idx == -1) {
return; return;
}
if (!url.startsWith(OAUTH_BASE_URL)) if (!url.startsWith(OAUTH_BASE_URL)) {
return; return;
}
code_idx += (int)uri.size(); code_idx += (int)uri.size();
int next_idx = url.indexOf("&", code_idx); int next_idx = url.indexOf("&", code_idx);
if (next_idx != -1) if (next_idx != -1) {
code = url.mid(code_idx, next_idx - code_idx); code = url.mid(code_idx, next_idx - code_idx);
else } else {
code = url.right(url.size() - code_idx); code = url.right(url.size() - code_idx);
}
accept(); accept();
} }
+9 -5
View File
@@ -21,10 +21,11 @@ OBSAbout::OBSAbout(QWidget *parent) : QDialog(parent), ui(new Ui::OBSAbout)
QString bitness; QString bitness;
if (sizeof(void *) == 4) if (sizeof(void *) == 4) {
bitness = " (32 bit)"; bitness = " (32 bit)";
else if (sizeof(void *) == 8) } else if (sizeof(void *) == 8) {
bitness = " (64 bit)"; bitness = " (64 bit)";
}
QString ver = obs_get_version_string(); QString ver = obs_get_version_string();
@@ -80,8 +81,9 @@ void OBSAbout::ShowAbout()
{ {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
if (main->patronJson.empty()) if (main->patronJson.empty()) {
return; return;
}
std::string error; std::string error;
Json json = Json::parse(main->patronJson, error); Json json = Json::parse(main->patronJson, error);
@@ -111,12 +113,14 @@ void OBSAbout::ShowAbout()
text += "\">"; text += "\">";
} }
text += QT_UTF8(name.c_str()).toHtmlEscaped(); text += QT_UTF8(name.c_str()).toHtmlEscaped();
if (!link.empty()) if (!link.empty()) {
text += "</a>"; text += "</a>";
}
if (first) if (first) {
first = false; first = false;
} }
}
ui->textBrowser->setHtml(text); ui->textBrowser->setHtml(text);
} }
+21 -11
View File
@@ -19,8 +19,9 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent) : QDialog(parent), ui(new Ui
VolumeType volType = (VolumeType)config_get_int(App()->GetUserConfig(), "BasicWindow", "AdvAudioVolumeType"); VolumeType volType = (VolumeType)config_get_int(App()->GetUserConfig(), "BasicWindow", "AdvAudioVolumeType");
if (volType == VolumeType::Percent) if (volType == VolumeType::Percent) {
ui->usePercent->setChecked(true); ui->usePercent->setChecked(true);
}
installEventFilter(CreateShortcutFilter()); installEventFilter(CreateShortcutFilter());
@@ -35,8 +36,9 @@ OBSBasicAdvAudio::~OBSBasicAdvAudio()
{ {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
for (size_t i = 0; i < controls.size(); ++i) for (size_t i = 0; i < controls.size(); ++i) {
delete controls[i]; delete controls[i];
}
main->SaveProject(); main->SaveProject();
} }
@@ -47,8 +49,9 @@ bool OBSBasicAdvAudio::EnumSources(void *param, obs_source_t *source)
uint32_t flags = obs_source_get_output_flags(source); uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) != 0 && if ((flags & OBS_SOURCE_AUDIO) != 0 &&
(dialog->showInactive || (obs_source_active(source) && obs_source_audio_active(source)))) (dialog->showInactive || (obs_source_active(source) && obs_source_audio_active(source)))) {
dialog->AddAudioSource(source); dialog->AddAudioSource(source);
}
return true; return true;
} }
@@ -71,17 +74,19 @@ void OBSBasicAdvAudio::OBSSourceActivated(void *param, calldata_t *calldata)
{ {
OBSSource source((obs_source_t *)calldata_ptr(calldata, "source")); OBSSource source((obs_source_t *)calldata_ptr(calldata, "source"));
if (obs_source_audio_active(source)) if (obs_source_audio_active(source)) {
QMetaObject::invokeMethod(static_cast<OBSBasicAdvAudio *>(param), "SourceAdded", QMetaObject::invokeMethod(static_cast<OBSBasicAdvAudio *>(param), "SourceAdded",
Q_ARG(OBSSource, source)); Q_ARG(OBSSource, source));
} }
}
inline void OBSBasicAdvAudio::AddAudioSource(obs_source_t *source) inline void OBSBasicAdvAudio::AddAudioSource(obs_source_t *source)
{ {
for (size_t i = 0; i < controls.size(); i++) { for (size_t i = 0; i < controls.size(); i++) {
if (controls[i]->GetSource() == source) if (controls[i]->GetSource() == source) {
return; return;
} }
}
OBSAdvAudioCtrl *control = new OBSAdvAudioCtrl(ui->mainLayout, source); OBSAdvAudioCtrl *control = new OBSAdvAudioCtrl(ui->mainLayout, source);
InsertQObjectByName(controls, control); InsertQObjectByName(controls, control);
@@ -95,8 +100,9 @@ void OBSBasicAdvAudio::SourceAdded(OBSSource source)
{ {
uint32_t flags = obs_source_get_output_flags(source); uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) == 0) if ((flags & OBS_SOURCE_AUDIO) == 0) {
return; return;
}
AddAudioSource(source); AddAudioSource(source);
} }
@@ -105,8 +111,9 @@ void OBSBasicAdvAudio::SourceRemoved(OBSSource source)
{ {
uint32_t flags = obs_source_get_output_flags(source); uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) == 0) if ((flags & OBS_SOURCE_AUDIO) == 0) {
return; return;
}
for (size_t i = 0; i < controls.size(); i++) { for (size_t i = 0; i < controls.size(); i++) {
if (controls[i]->GetSource() == source) { if (controls[i]->GetSource() == source) {
@@ -121,13 +128,15 @@ void OBSBasicAdvAudio::on_usePercent_toggled(bool checked)
{ {
VolumeType type; VolumeType type;
if (checked) if (checked) {
type = VolumeType::Percent; type = VolumeType::Percent;
else } else {
type = VolumeType::dB; type = VolumeType::dB;
}
for (size_t i = 0; i < controls.size(); i++) for (size_t i = 0; i < controls.size(); i++) {
controls[i]->SetVolumeWidget(type); controls[i]->SetVolumeWidget(type);
}
config_set_int(App()->GetUserConfig(), "BasicWindow", "AdvAudioVolumeType", (int)type); config_set_int(App()->GetUserConfig(), "BasicWindow", "AdvAudioVolumeType", (int)type);
} }
@@ -139,8 +148,9 @@ void OBSBasicAdvAudio::on_activeOnly_toggled(bool checked)
void OBSBasicAdvAudio::SetShowInactive(bool show) void OBSBasicAdvAudio::SetShowInactive(bool show)
{ {
if (showInactive == show) if (showInactive == show) {
return; return;
}
showInactive = show; showInactive = show;
+88 -48
View File
@@ -111,8 +111,9 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
ui->effectFilters->setFocus(); ui->effectFilters->setFocus();
} }
if (audioOnly || (audio && !async)) if (audioOnly || (audio && !async)) {
ui->asyncLabel->setText(QTStr("Basic.Filters.AudioFilters")); ui->asyncLabel->setText(QTStr("Basic.Filters.AudioFilters"));
}
if (async && audio && ui->asyncFilters->count() == 0) { if (async && audio && ui->asyncFilters->count() == 0) {
UpdateSplitter(false); UpdateSplitter(false);
@@ -132,8 +133,9 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
if ((caps & OBS_SOURCE_VIDEO) != 0) { if ((caps & OBS_SOURCE_VIDEO) != 0) {
ui->rightLayout->setContentsMargins(0, 0, 0, 0); ui->rightLayout->setContentsMargins(0, 0, 0, 0);
ui->preview->show(); ui->preview->show();
if (drawable_type) if (drawable_type) {
connect(ui->preview, &OBSQTDisplay::DisplayCreated, this, addDrawCallback); connect(ui->preview, &OBSQTDisplay::DisplayCreated, this, addDrawCallback);
}
} else { } else {
ui->rightLayout->setContentsMargins(0, noPreviewMargin, 0, 0); ui->rightLayout->setContentsMargins(0, noPreviewMargin, 0, 0);
ui->preview->hide(); ui->preview->hide();
@@ -162,13 +164,15 @@ void OBSBasicFilters::Init()
inline OBSSource OBSBasicFilters::GetFilter(int row, bool async) inline OBSSource OBSBasicFilters::GetFilter(int row, bool async)
{ {
if (row == -1) if (row == -1) {
return OBSSource(); return OBSSource();
}
QListWidget *list = async ? ui->asyncFilters : ui->effectFilters; QListWidget *list = async ? ui->asyncFilters : ui->effectFilters;
QListWidgetItem *item = list->item(row); QListWidgetItem *item = list->item(row);
if (!item) if (!item) {
return OBSSource(); return OBSSource();
}
QVariant v = item->data(Qt::UserRole); QVariant v = item->data(Qt::UserRole);
return v.value<OBSSource>(); return v.value<OBSSource>();
@@ -244,8 +248,9 @@ void OBSBasicFilters::UpdatePropertiesView(int row, bool async)
} }
} }
if (!filter) if (!filter) {
return; return;
}
OBSDataAutoRelease settings = obs_source_get_settings(filter); OBSDataAutoRelease settings = obs_source_get_settings(filter);
@@ -287,8 +292,9 @@ void OBSBasicFilters::AddFilter(OBSSource filter, bool focus)
item->setData(Qt::UserRole, QVariant::fromValue(filter)); item->setData(Qt::UserRole, QVariant::fromValue(filter));
list->addItem(item); list->addItem(item);
if (focus) if (focus) {
list->setCurrentItem(item); list->setCurrentItem(item);
}
SetupVisibilityItem(list, item, filter); SetupVisibilityItem(list, item, filter);
} }
@@ -312,8 +318,9 @@ void OBSBasicFilters::RemoveFilter(OBSSource filter)
const char *filterName = obs_source_get_name(filter); const char *filterName = obs_source_get_name(filter);
const char *sourceName = obs_source_get_name(source); const char *sourceName = obs_source_get_name(source);
if (!sourceName || !filterName) if (!sourceName || !filterName) {
return; return;
}
const char *filterId = obs_source_get_id(filter); const char *filterId = obs_source_get_id(filter);
@@ -348,10 +355,11 @@ void OBSBasicFilters::ReorderFilter(QListWidget *list, obs_source_t *filter, siz
list->insertItem((int)idx, listItem); list->insertItem((int)idx, listItem);
SetupVisibilityItem(list, listItem, filterItem); SetupVisibilityItem(list, listItem, filterItem);
if (sel) if (sel) {
list->setCurrentRow((int)idx); list->setCurrentRow((int)idx);
} }
} }
}
break; break;
} }
@@ -383,8 +391,9 @@ void OBSBasicFilters::ReorderFilters()
void OBSBasicFilters::UpdateFilters() void OBSBasicFilters::UpdateFilters()
{ {
if (!source) if (!source) {
return; return;
}
ClearListItems(ui->effectFilters); ClearListItems(ui->effectFilters);
ClearListItems(ui->asyncFilters); ClearListItems(ui->asyncFilters);
@@ -417,8 +426,9 @@ void OBSBasicFilters::UpdateSplitter(bool show_splitter_frame)
{ {
bool show_splitter_handle = show_splitter_frame; bool show_splitter_handle = show_splitter_frame;
uint32_t caps = obs_source_get_output_flags(source); uint32_t caps = obs_source_get_output_flags(source);
if ((caps & OBS_SOURCE_VIDEO) == 0) if ((caps & OBS_SOURCE_VIDEO) == 0) {
show_splitter_handle = false; show_splitter_handle = false;
}
for (int i = 0; i < ui->rightLayout->count(); i++) { for (int i = 0; i < ui->rightLayout->count(); i++) {
QSplitterHandle *hndl = ui->rightLayout->handle(i); QSplitterHandle *hndl = ui->rightLayout->handle(i);
@@ -438,8 +448,9 @@ static bool filter_compatible(bool async, uint32_t sourceFlags, uint32_t filterF
bool asyncSource = (sourceFlags & OBS_SOURCE_ASYNC) != 0; bool asyncSource = (sourceFlags & OBS_SOURCE_ASYNC) != 0;
if (async && ((audioOnly && filterVideo) || (!audio && !asyncSource) || (filterAudio && !audio) || if (async && ((audioOnly && filterVideo) || (!audio && !asyncSource) || (filterAudio && !audio) ||
(!asyncSource && !filterAudio))) (!asyncSource && !filterAudio))) {
return false; return false;
}
return (async && (filterAudio || filterAsync)) || (!async && !filterAudio && !filterAsync); return (async && (filterAudio || filterAsync)) || (!async && !filterAudio && !filterAsync);
} }
@@ -465,12 +476,15 @@ QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
const char *name = obs_source_get_display_name(type_str); const char *name = obs_source_get_display_name(type_str);
uint32_t caps = obs_get_source_output_flags(type_str); uint32_t caps = obs_get_source_output_flags(type_str);
if ((caps & OBS_SOURCE_DEPRECATED) != 0) if ((caps & OBS_SOURCE_DEPRECATED) != 0) {
continue; continue;
if ((caps & OBS_SOURCE_CAP_DISABLED) != 0) }
if ((caps & OBS_SOURCE_CAP_DISABLED) != 0) {
continue; continue;
if ((caps & OBS_SOURCE_CAP_OBSOLETE) != 0) }
if ((caps & OBS_SOURCE_CAP_OBSOLETE) != 0) {
continue; continue;
}
types.emplace_back(type_str, name); types.emplace_back(type_str, name);
} }
@@ -481,8 +495,9 @@ QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
for (FilterInfo &type : types) { for (FilterInfo &type : types) {
uint32_t filterFlags = obs_get_source_output_flags(type.type.c_str()); uint32_t filterFlags = obs_get_source_output_flags(type.type.c_str());
if (!filter_compatible(async, sourceFlags, filterFlags)) if (!filter_compatible(async, sourceFlags, filterFlags)) {
continue; continue;
}
QAction *popupItem = new QAction(QT_UTF8(type.name.c_str()), this); QAction *popupItem = new QAction(QT_UTF8(type.name.c_str()), this);
popupItem->setData(QT_UTF8(type.type.c_str())); popupItem->setData(QT_UTF8(type.type.c_str()));
@@ -515,8 +530,9 @@ void OBSBasicFilters::AddNewFilter(const char *id)
bool success = NameDialog::AskForName(this, QTStr("Basic.Filters.AddFilter.Title"), bool success = NameDialog::AskForName(this, QTStr("Basic.Filters.AddFilter.Title"),
QTStr("Basic.Filters.AddFilter.Text"), name, text); QTStr("Basic.Filters.AddFilter.Text"), name, text);
if (!success) if (!success) {
return; return;
}
if (name.empty()) { if (name.empty()) {
OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text")); OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text"));
@@ -586,8 +602,9 @@ void OBSBasicFilters::AddNewFilter(const char *id)
void OBSBasicFilters::closeEvent(QCloseEvent *event) void OBSBasicFilters::closeEvent(QCloseEvent *event)
{ {
QDialog::closeEvent(event); QDialog::closeEvent(event);
if (!event->isAccepted()) if (!event->isAccepted()) {
return; return;
}
obs_display_remove_draw_callback(ui->preview->GetDisplay(), OBSBasicFilters::DrawPreview, this); obs_display_remove_draw_callback(ui->preview->GetDisplay(), OBSBasicFilters::DrawPreview, this);
@@ -656,8 +673,9 @@ void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy)
{ {
OBSBasicFilters *window = static_cast<OBSBasicFilters *>(data); OBSBasicFilters *window = static_cast<OBSBasicFilters *>(data);
if (!window->source) if (!window->source) {
return; return;
}
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u); uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u); uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
@@ -707,32 +725,36 @@ void OBSBasicFilters::on_addAsyncFilter_clicked()
{ {
ui->asyncFilters->setFocus(); ui->asyncFilters->setFocus();
QScopedPointer<QMenu> popup(CreateAddFilterPopupMenu(true)); QScopedPointer<QMenu> popup(CreateAddFilterPopupMenu(true));
if (popup) if (popup) {
popup->exec(QCursor::pos()); popup->exec(QCursor::pos());
} }
}
void OBSBasicFilters::on_removeAsyncFilter_clicked() void OBSBasicFilters::on_removeAsyncFilter_clicked()
{ {
OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true); OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true);
if (filter) { if (filter) {
if (QueryRemove(this, filter)) if (QueryRemove(this, filter)) {
delete_filter(filter); delete_filter(filter);
} }
} }
}
void OBSBasicFilters::on_moveAsyncFilterUp_clicked() void OBSBasicFilters::on_moveAsyncFilterUp_clicked()
{ {
OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true); OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true);
if (filter) if (filter) {
obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_UP); obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_UP);
} }
}
void OBSBasicFilters::on_moveAsyncFilterDown_clicked() void OBSBasicFilters::on_moveAsyncFilterDown_clicked()
{ {
OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true); OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true);
if (filter) if (filter) {
obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_DOWN); obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_DOWN);
} }
}
void OBSBasicFilters::on_asyncFilters_GotFocus() void OBSBasicFilters::on_asyncFilters_GotFocus()
{ {
@@ -749,9 +771,10 @@ void OBSBasicFilters::on_addEffectFilter_clicked()
{ {
ui->effectFilters->setFocus(); ui->effectFilters->setFocus();
QScopedPointer<QMenu> popup(CreateAddFilterPopupMenu(false)); QScopedPointer<QMenu> popup(CreateAddFilterPopupMenu(false));
if (popup) if (popup) {
popup->exec(QCursor::pos()); popup->exec(QCursor::pos());
} }
}
void OBSBasicFilters::on_removeEffectFilter_clicked() void OBSBasicFilters::on_removeEffectFilter_clicked()
{ {
@@ -766,16 +789,18 @@ void OBSBasicFilters::on_removeEffectFilter_clicked()
void OBSBasicFilters::on_moveEffectFilterUp_clicked() void OBSBasicFilters::on_moveEffectFilterUp_clicked()
{ {
OBSSource filter = GetFilter(ui->effectFilters->currentRow(), false); OBSSource filter = GetFilter(ui->effectFilters->currentRow(), false);
if (filter) if (filter) {
obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_UP); obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_UP);
} }
}
void OBSBasicFilters::on_moveEffectFilterDown_clicked() void OBSBasicFilters::on_moveEffectFilterDown_clicked()
{ {
OBSSource filter = GetFilter(ui->effectFilters->currentRow(), false); OBSSource filter = GetFilter(ui->effectFilters->currentRow(), false);
if (filter) if (filter) {
obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_DOWN); obs_source_filter_set_order(source, filter, OBS_ORDER_MOVE_DOWN);
} }
}
void OBSBasicFilters::on_effectFilters_GotFocus() void OBSBasicFilters::on_effectFilters_GotFocus()
{ {
@@ -790,35 +815,39 @@ void OBSBasicFilters::on_effectFilters_currentRowChanged(int row)
void OBSBasicFilters::on_actionRemoveFilter_triggered() void OBSBasicFilters::on_actionRemoveFilter_triggered()
{ {
if (ui->asyncFilters->hasFocus()) if (ui->asyncFilters->hasFocus()) {
on_removeAsyncFilter_clicked(); on_removeAsyncFilter_clicked();
else if (ui->effectFilters->hasFocus()) } else if (ui->effectFilters->hasFocus()) {
on_removeEffectFilter_clicked(); on_removeEffectFilter_clicked();
} }
}
void OBSBasicFilters::on_actionMoveUp_triggered() void OBSBasicFilters::on_actionMoveUp_triggered()
{ {
if (ui->asyncFilters->hasFocus()) if (ui->asyncFilters->hasFocus()) {
on_moveAsyncFilterUp_clicked(); on_moveAsyncFilterUp_clicked();
else if (ui->effectFilters->hasFocus()) } else if (ui->effectFilters->hasFocus()) {
on_moveEffectFilterUp_clicked(); on_moveEffectFilterUp_clicked();
} }
}
void OBSBasicFilters::on_actionMoveDown_triggered() void OBSBasicFilters::on_actionMoveDown_triggered()
{ {
if (ui->asyncFilters->hasFocus()) if (ui->asyncFilters->hasFocus()) {
on_moveAsyncFilterDown_clicked(); on_moveAsyncFilterDown_clicked();
else if (ui->effectFilters->hasFocus()) } else if (ui->effectFilters->hasFocus()) {
on_moveEffectFilterDown_clicked(); on_moveEffectFilterDown_clicked();
} }
}
void OBSBasicFilters::on_actionRenameFilter_triggered() void OBSBasicFilters::on_actionRenameFilter_triggered()
{ {
if (ui->asyncFilters->hasFocus()) if (ui->asyncFilters->hasFocus()) {
RenameAsyncFilter(); RenameAsyncFilter();
else if (ui->effectFilters->hasFocus()) } else if (ui->effectFilters->hasFocus()) {
RenameEffectFilter(); RenameEffectFilter();
} }
}
void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async) void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
{ {
@@ -828,8 +857,9 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
QMenu popup(window()); QMenu popup(window());
QPointer<QMenu> addMenu = CreateAddFilterPopupMenu(async); QPointer<QMenu> addMenu = CreateAddFilterPopupMenu(async);
if (addMenu) if (addMenu) {
popup.addMenu(addMenu); popup.addMenu(addMenu);
}
if (item) { if (item) {
popup.addSeparator(); popup.addSeparator();
@@ -862,8 +892,9 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async) void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async)
{ {
if (editActive) if (editActive) {
return; return;
}
Qt::ItemFlags flags = item->flags(); Qt::ItemFlags flags = item->flags();
OBSSource filter = item->data(Qt::UserRole).value<OBSSource>(); OBSSource filter = item->data(Qt::UserRole).value<OBSSource>();
@@ -893,8 +924,9 @@ void OBSBasicFilters::DuplicateItem(QListWidgetItem *item)
bool success = NameDialog::AskForName(this, QTStr("Basic.Filters.AddFilter.Title"), bool success = NameDialog::AskForName(this, QTStr("Basic.Filters.AddFilter.Title"),
QTStr("Basic.Filters.AddFilter.Text"), name, text); QTStr("Basic.Filters.AddFilter.Text"), name, text);
if (!success) if (!success) {
return; return;
}
if (name.empty()) { if (name.empty()) {
OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text")); OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text"));
@@ -953,8 +985,9 @@ void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list)
bool sameName = (name == prevName); bool sameName = (name == prevName);
OBSSourceAutoRelease foundFilter = nullptr; OBSSourceAutoRelease foundFilter = nullptr;
if (!sameName) if (!sameName) {
foundFilter = obs_source_get_filter_by_name(source, name.c_str()); foundFilter = obs_source_get_filter_by_name(source, name.c_str());
}
if (foundFilter || name.empty() || sameName) { if (foundFilter || name.empty() || sameName) {
listItem->setText(QT_UTF8(prevName)); listItem->setText(QT_UTF8(prevName));
@@ -1015,11 +1048,13 @@ void OBSBasicFilters::ResetFilters()
OBSSource filter = GetFilter(row, isAsync); OBSSource filter = GetFilter(row, isAsync);
if (!filter) if (!filter) {
return; return;
}
if (!ConfirmReset(this)) if (!ConfirmReset(this)) {
return; return;
}
OBSDataAutoRelease settings = obs_source_get_settings(filter); OBSDataAutoRelease settings = obs_source_get_settings(filter);
@@ -1028,8 +1063,9 @@ void OBSBasicFilters::ResetFilters()
obs_data_clear(settings); obs_data_clear(settings);
if (!view->DeferUpdate()) if (!view->DeferUpdate()) {
obs_source_update(filter, nullptr); obs_source_update(filter, nullptr);
}
view->ReloadProperties(); view->ReloadProperties();
} }
@@ -1038,10 +1074,11 @@ void OBSBasicFilters::CopyFilter()
{ {
OBSSource filter = nullptr; OBSSource filter = nullptr;
if (isAsync) if (isAsync) {
filter = GetFilter(ui->asyncFilters->currentRow(), true); filter = GetFilter(ui->asyncFilters->currentRow(), true);
else } else {
filter = GetFilter(ui->effectFilters->currentRow(), false); filter = GetFilter(ui->effectFilters->currentRow(), false);
}
main->copyFilter = OBSGetWeakRef(filter); main->copyFilter = OBSGetWeakRef(filter);
} }
@@ -1049,8 +1086,9 @@ void OBSBasicFilters::CopyFilter()
void OBSBasicFilters::PasteFilter() void OBSBasicFilters::PasteFilter()
{ {
OBSSource filter = OBSGetStrongRef(main->copyFilter); OBSSource filter = OBSGetStrongRef(main->copyFilter);
if (!filter) if (!filter) {
return; return;
}
OBSDataArrayAutoRelease undo_array = obs_source_backup_filters(source); OBSDataArrayAutoRelease undo_array = obs_source_backup_filters(source);
obs_source_copy_single_filter(source, filter); obs_source_copy_single_filter(source, filter);
@@ -1105,17 +1143,19 @@ void OBSBasicFilters::FiltersMoved(const QModelIndex &, int srcIdxStart, int, co
QListWidget *list = isAsync ? ui->asyncFilters : ui->effectFilters; QListWidget *list = isAsync ? ui->asyncFilters : ui->effectFilters;
int neighborIdx = 0; int neighborIdx = 0;
if (srcIdxStart < list->currentRow()) if (srcIdxStart < list->currentRow()) {
neighborIdx = list->currentRow() - 1; neighborIdx = list->currentRow() - 1;
else if (srcIdxStart > list->currentRow()) } else if (srcIdxStart > list->currentRow()) {
neighborIdx = list->currentRow() + 1; neighborIdx = list->currentRow() + 1;
else } else {
return; return;
}
if (neighborIdx > list->count() - 1) if (neighborIdx > list->count() - 1) {
neighborIdx = list->count() - 1; neighborIdx = list->count() - 1;
else if (neighborIdx < 0) } else if (neighborIdx < 0) {
neighborIdx = 0; neighborIdx = 0;
}
OBSSource neighbor = GetFilter(neighborIdx, isAsync); OBSSource neighbor = GetFilter(neighborIdx, isAsync);
int idx = obs_source_filter_get_index(source, neighbor); int idx = obs_source_filter_get_index(source, neighbor);
+2 -1
View File
@@ -115,9 +115,10 @@ public:
inline void UpdateSource(obs_source_t *target) inline void UpdateSource(obs_source_t *target)
{ {
if (source == target) if (source == target) {
UpdateFilters(); UpdateFilters();
} }
}
protected: protected:
virtual void closeEvent(QCloseEvent *event) override; virtual void closeEvent(QCloseEvent *event) override;
+39 -21
View File
@@ -59,8 +59,9 @@ OBSBasicInteraction::OBSBasicInteraction(QWidget *parent, OBSSource source_)
ui->preview->setFocusPolicy(Qt::StrongFocus); ui->preview->setFocusPolicy(Qt::StrongFocus);
ui->preview->installEventFilter(eventFilter.get()); ui->preview->installEventFilter(eventFilter.get());
if (cx > 400 && cy > 400) if (cx > 400 && cy > 400) {
resize(cx, cy); resize(cx, cy);
}
const char *name = obs_source_get_name(source); const char *name = obs_source_get_name(source);
setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name))); setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)));
@@ -123,8 +124,9 @@ void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
{ {
OBSBasicInteraction *window = static_cast<OBSBasicInteraction *>(data); OBSBasicInteraction *window = static_cast<OBSBasicInteraction *>(data);
if (!window->source) if (!window->source) {
return; return;
}
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u); uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u); uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
@@ -154,8 +156,9 @@ void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
void OBSBasicInteraction::closeEvent(QCloseEvent *event) void OBSBasicInteraction::closeEvent(QCloseEvent *event)
{ {
QDialog::closeEvent(event); QDialog::closeEvent(event);
if (!event->isAccepted()) if (!event->isAccepted()) {
return; return;
}
config_set_int(App()->GetAppConfig(), "InteractionWindow", "cx", width()); config_set_int(App()->GetAppConfig(), "InteractionWindow", "cx", width());
config_set_int(App()->GetAppConfig(), "InteractionWindow", "cy", height()); config_set_int(App()->GetAppConfig(), "InteractionWindow", "cy", height());
@@ -189,26 +192,32 @@ static int TranslateQtKeyboardEventModifiers(QInputEvent *event, bool mouseEvent
{ {
int obsModifiers = INTERACT_NONE; int obsModifiers = INTERACT_NONE;
if (event->modifiers().testFlag(Qt::ShiftModifier)) if (event->modifiers().testFlag(Qt::ShiftModifier)) {
obsModifiers |= INTERACT_SHIFT_KEY; obsModifiers |= INTERACT_SHIFT_KEY;
if (event->modifiers().testFlag(Qt::AltModifier)) }
if (event->modifiers().testFlag(Qt::AltModifier)) {
obsModifiers |= INTERACT_ALT_KEY; obsModifiers |= INTERACT_ALT_KEY;
}
#ifdef __APPLE__ #ifdef __APPLE__
// Mac: Meta = Control, Control = Command // Mac: Meta = Control, Control = Command
if (event->modifiers().testFlag(Qt::ControlModifier)) if (event->modifiers().testFlag(Qt::ControlModifier)) {
obsModifiers |= INTERACT_COMMAND_KEY; obsModifiers |= INTERACT_COMMAND_KEY;
if (event->modifiers().testFlag(Qt::MetaModifier)) }
if (event->modifiers().testFlag(Qt::MetaModifier)) {
obsModifiers |= INTERACT_CONTROL_KEY; obsModifiers |= INTERACT_CONTROL_KEY;
}
#else #else
// Handle windows key? Can a browser even trap that key? // Handle windows key? Can a browser even trap that key?
if (event->modifiers().testFlag(Qt::ControlModifier)) if (event->modifiers().testFlag(Qt::ControlModifier)) {
obsModifiers |= INTERACT_CONTROL_KEY; obsModifiers |= INTERACT_CONTROL_KEY;
}
#endif #endif
if (!mouseEvent) { if (!mouseEvent) {
if (event->modifiers().testFlag(Qt::KeypadModifier)) if (event->modifiers().testFlag(Qt::KeypadModifier)) {
obsModifiers |= INTERACT_IS_KEY_PAD; obsModifiers |= INTERACT_IS_KEY_PAD;
} }
}
return obsModifiers; return obsModifiers;
} }
@@ -217,12 +226,15 @@ static int TranslateQtMouseEventModifiers(QMouseEvent *event)
{ {
int modifiers = TranslateQtKeyboardEventModifiers(event, true); int modifiers = TranslateQtKeyboardEventModifiers(event, true);
if (event->buttons().testFlag(Qt::LeftButton)) if (event->buttons().testFlag(Qt::LeftButton)) {
modifiers |= INTERACT_MOUSE_LEFT; modifiers |= INTERACT_MOUSE_LEFT;
if (event->buttons().testFlag(Qt::MiddleButton)) }
if (event->buttons().testFlag(Qt::MiddleButton)) {
modifiers |= INTERACT_MOUSE_MIDDLE; modifiers |= INTERACT_MOUSE_MIDDLE;
if (event->buttons().testFlag(Qt::RightButton)) }
if (event->buttons().testFlag(Qt::RightButton)) {
modifiers |= INTERACT_MOUSE_RIGHT; modifiers |= INTERACT_MOUSE_RIGHT;
}
return modifiers; return modifiers;
} }
@@ -252,10 +264,12 @@ bool OBSBasicInteraction::GetSourceRelativeXY(int mouseX, int mouseY, int &relX,
} }
// Confirm mouse is inside the source // Confirm mouse is inside the source
if (relX < 0 || relX > int(sourceCX)) if (relX < 0 || relX > int(sourceCX)) {
return false; return false;
if (relY < 0 || relY > int(sourceCY)) }
if (relY < 0 || relY > int(sourceCY)) {
return false; return false;
}
return true; return true;
} }
@@ -264,8 +278,9 @@ bool OBSBasicInteraction::HandleMouseClickEvent(QMouseEvent *event)
{ {
bool mouseUp = event->type() == QEvent::MouseButtonRelease; bool mouseUp = event->type() == QEvent::MouseButtonRelease;
int clickCount = 1; int clickCount = 1;
if (event->type() == QEvent::MouseButtonDblClick) if (event->type() == QEvent::MouseButtonDblClick) {
clickCount = 2; clickCount = 2;
}
struct obs_mouse_event mouseEvent = {}; struct obs_mouse_event mouseEvent = {};
@@ -295,8 +310,9 @@ bool OBSBasicInteraction::HandleMouseClickEvent(QMouseEvent *event)
QPoint pos = event->pos(); QPoint pos = event->pos();
bool insideSource = GetSourceRelativeXY(pos.x(), pos.y(), mouseEvent.x, mouseEvent.y); bool insideSource = GetSourceRelativeXY(pos.x(), pos.y(), mouseEvent.x, mouseEvent.y);
if (mouseUp || insideSource) if (mouseUp || insideSource) {
obs_source_send_mouse_click(source, &mouseEvent, button, mouseUp, clickCount); obs_source_send_mouse_click(source, &mouseEvent, button, mouseUp, clickCount);
}
return true; return true;
} }
@@ -329,16 +345,18 @@ bool OBSBasicInteraction::HandleMouseWheelEvent(QWheelEvent *event)
const QPoint angleDelta = event->angleDelta(); const QPoint angleDelta = event->angleDelta();
if (!event->pixelDelta().isNull()) { if (!event->pixelDelta().isNull()) {
if (angleDelta.x()) if (angleDelta.x()) {
xDelta = event->pixelDelta().x(); xDelta = event->pixelDelta().x();
else
yDelta = event->pixelDelta().y();
} else { } else {
if (angleDelta.x()) yDelta = event->pixelDelta().y();
}
} else {
if (angleDelta.x()) {
xDelta = angleDelta.x(); xDelta = angleDelta.x();
else } else {
yDelta = angleDelta.y(); yDelta = angleDelta.y();
} }
}
const QPointF position = event->position(); const QPointF position = event->position();
const int x = position.x(); const int x = position.x();
+17 -9
View File
@@ -59,8 +59,9 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
ui->setupUi(this); ui->setupUi(this);
ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
if (cx > 400 && cy > 400) if (cx > 400 && cy > 400) {
resize(cx, cy); resize(cx, cy);
}
/* The OBSData constructor increments the reference once */ /* The OBSData constructor increments the reference once */
obs_data_release(oldSettings); obs_data_release(oldSettings);
@@ -321,24 +322,27 @@ void OBSBasicProperties::on_buttonBox_clicked(QAbstractButton *button)
std::string undo_data(obs_data_get_json(oldSettings)); std::string undo_data(obs_data_get_json(oldSettings));
std::string redo_data(obs_data_get_json(new_settings)); std::string redo_data(obs_data_get_json(new_settings));
if (undo_data.compare(redo_data) != 0) if (undo_data.compare(redo_data) != 0) {
main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo, main->undo_s.add_action(QTStr("Undo.Properties").arg(obs_source_get_name(source)), undo_redo,
undo_redo, undo_data, redo_data); undo_redo, undo_data, redo_data);
}
acceptClicked = true; acceptClicked = true;
close(); close();
if (view->DeferUpdate()) if (view->DeferUpdate()) {
view->UpdateSettings(); view->UpdateSettings();
}
} else if (val == QDialogButtonBox::RejectRole) { } else if (val == QDialogButtonBox::RejectRole) {
OBSDataAutoRelease settings = obs_source_get_settings(source); OBSDataAutoRelease settings = obs_source_get_settings(source);
obs_data_clear(settings); obs_data_clear(settings);
if (view->DeferUpdate()) if (view->DeferUpdate()) {
obs_data_apply(settings, oldSettings); obs_data_apply(settings, oldSettings);
else } else {
obs_source_update(source, oldSettings); obs_source_update(source, oldSettings);
}
close(); close();
} }
@@ -348,8 +352,9 @@ void OBSBasicProperties::DrawPreview(void *data, uint32_t cx, uint32_t cy)
{ {
OBSBasicProperties *window = static_cast<OBSBasicProperties *>(data); OBSBasicProperties *window = static_cast<OBSBasicProperties *>(data);
if (!window->source) if (!window->source) {
return; return;
}
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u); uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u); uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
@@ -380,8 +385,9 @@ void OBSBasicProperties::DrawTransitionPreview(void *data, uint32_t cx, uint32_t
{ {
OBSBasicProperties *window = static_cast<OBSBasicProperties *>(data); OBSBasicProperties *window = static_cast<OBSBasicProperties *>(data);
if (!window->sourceClone) if (!window->sourceClone) {
return; return;
}
uint32_t sourceCX = max(obs_source_get_width(window->sourceClone), 1u); uint32_t sourceCX = max(obs_source_get_width(window->sourceClone), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->sourceClone), 1u); uint32_t sourceCY = max(obs_source_get_height(window->sourceClone), 1u);
@@ -430,9 +436,10 @@ void OBSBasicProperties::reject()
void OBSBasicProperties::closeEvent(QCloseEvent *event) void OBSBasicProperties::closeEvent(QCloseEvent *event)
{ {
QDialog::closeEvent(event); QDialog::closeEvent(event);
if (event->isAccepted()) if (event->isAccepted()) {
Cleanup(); Cleanup();
} }
}
bool OBSBasicProperties::nativeEvent(const QByteArray &, void *message, qintptr *) bool OBSBasicProperties::nativeEvent(const QByteArray &, void *message, qintptr *)
{ {
@@ -481,8 +488,9 @@ bool OBSBasicProperties::ConfirmQuit()
switch (button) { switch (button) {
case QMessageBox::Save: case QMessageBox::Save:
acceptClicked = true; acceptClicked = true;
if (view->DeferUpdate()) if (view->DeferUpdate()) {
view->UpdateSettings(); view->UpdateSettings();
}
// Do nothing because the settings are already updated // Do nothing because the settings are already updated
break; break;
case QMessageBox::Discard: case QMessageBox::Discard:
+22 -11
View File
@@ -130,11 +130,12 @@ OBSBasicTransform::~OBSBasicTransform()
}; };
std::string redo_data(obs_data_get_json(wrapper)); std::string redo_data(obs_data_get_json(wrapper));
if (undo_data.compare(redo_data) != 0) if (undo_data.compare(redo_data) != 0) {
main->undo_s.add_action( main->undo_s.add_action(
QTStr("Undo.Transform").arg(obs_source_get_name(obs_scene_get_source(main->GetCurrentScene()))), QTStr("Undo.Transform").arg(obs_source_get_name(obs_scene_get_source(main->GetCurrentScene()))),
undo_redo, undo_redo, undo_data, redo_data); undo_redo, undo_redo, undo_data, redo_data);
} }
}
void OBSBasicTransform::setScene(OBSScene scene) void OBSBasicTransform::setScene(OBSScene scene)
{ {
@@ -168,8 +169,9 @@ void OBSBasicTransform::setEnabled(bool enable)
void OBSBasicTransform::setItemQt(OBSSceneItem newItem) void OBSBasicTransform::setItemQt(OBSSceneItem newItem)
{ {
item = newItem; item = newItem;
if (item) if (item) {
refreshControls(); refreshControls();
}
bool enable = !!item && !obs_sceneitem_locked(item); bool enable = !!item && !obs_sceneitem_locked(item);
setEnabled(enable); setEnabled(enable);
@@ -180,9 +182,10 @@ void OBSBasicTransform::OBSSceneItemTransform(void *param, calldata_t *data)
OBSBasicTransform *window = static_cast<OBSBasicTransform *>(param); OBSBasicTransform *window = static_cast<OBSBasicTransform *>(param);
OBSSceneItem item = (obs_sceneitem_t *)calldata_ptr(data, "item"); OBSSceneItem item = (obs_sceneitem_t *)calldata_ptr(data, "item");
if (item == window->item && !window->ignoreTransformSignal) if (item == window->item && !window->ignoreTransformSignal) {
QMetaObject::invokeMethod(window, "refreshControls"); QMetaObject::invokeMethod(window, "refreshControls");
} }
}
void OBSBasicTransform::OBSSceneItemRemoved(void *param, calldata_t *data) void OBSBasicTransform::OBSSceneItemRemoved(void *param, calldata_t *data)
{ {
@@ -190,18 +193,20 @@ void OBSBasicTransform::OBSSceneItemRemoved(void *param, calldata_t *data)
obs_scene_t *scene = (obs_scene_t *)calldata_ptr(data, "scene"); obs_scene_t *scene = (obs_scene_t *)calldata_ptr(data, "scene");
obs_sceneitem_t *item = (obs_sceneitem_t *)calldata_ptr(data, "item"); obs_sceneitem_t *item = (obs_sceneitem_t *)calldata_ptr(data, "item");
if (item == window->item) if (item == window->item) {
window->setItem(FindASelectedItem(scene)); window->setItem(FindASelectedItem(scene));
} }
}
void OBSBasicTransform::OBSSceneItemSelect(void *param, calldata_t *data) void OBSBasicTransform::OBSSceneItemSelect(void *param, calldata_t *data)
{ {
OBSBasicTransform *window = static_cast<OBSBasicTransform *>(param); OBSBasicTransform *window = static_cast<OBSBasicTransform *>(param);
OBSSceneItem item = (obs_sceneitem_t *)calldata_ptr(data, "item"); OBSSceneItem item = (obs_sceneitem_t *)calldata_ptr(data, "item");
if (item != window->item) if (item != window->item) {
window->setItem(item); window->setItem(item);
} }
}
void OBSBasicTransform::OBSSceneItemDeselect(void *param, calldata_t *data) void OBSBasicTransform::OBSSceneItemDeselect(void *param, calldata_t *data)
{ {
@@ -237,8 +242,9 @@ static int alignToIndex(uint32_t align)
{ {
int index = 0; int index = 0;
for (uint32_t curAlign : indexToAlign) { for (uint32_t curAlign : indexToAlign) {
if (curAlign == align) if (curAlign == align) {
return index; return index;
}
index++; index++;
} }
@@ -248,8 +254,9 @@ static int alignToIndex(uint32_t align)
void OBSBasicTransform::refreshControls() void OBSBasicTransform::refreshControls()
{ {
if (!item) if (!item) {
return; return;
}
obs_transform_info oti; obs_transform_info oti;
obs_sceneitem_crop crop; obs_sceneitem_crop crop;
@@ -333,8 +340,9 @@ void OBSBasicTransform::onAlignChanged(int index)
void OBSBasicTransform::onBoundsType(int index) void OBSBasicTransform::onBoundsType(int index)
{ {
if (index == -1) if (index == -1) {
return; return;
}
obs_bounds_type type = (obs_bounds_type)index; obs_bounds_type type = (obs_bounds_type)index;
bool enable = (type != OBS_BOUNDS_NONE); bool enable = (type != OBS_BOUNDS_NONE);
@@ -405,8 +413,9 @@ void OBSBasicTransform::onBoundsType(int index)
void OBSBasicTransform::onControlChanged() void OBSBasicTransform::onControlChanged()
{ {
if (ignoreItemChange) if (ignoreItemChange) {
return; return;
}
obs_source_t *source = obs_sceneitem_get_source(item); obs_source_t *source = obs_sceneitem_get_source(item);
uint32_t source_cx = obs_source_get_width(source); uint32_t source_cx = obs_source_get_width(source);
@@ -441,8 +450,9 @@ void OBSBasicTransform::onControlChanged()
void OBSBasicTransform::onCropChanged() void OBSBasicTransform::onCropChanged()
{ {
if (ignoreItemChange) if (ignoreItemChange) {
return; return;
}
obs_sceneitem_crop crop; obs_sceneitem_crop crop;
crop.left = uint32_t(ui->cropLeft->value()); crop.left = uint32_t(ui->cropLeft->value());
@@ -457,8 +467,9 @@ void OBSBasicTransform::onCropChanged()
void OBSBasicTransform::onSceneChanged(QListWidgetItem *current, QListWidgetItem *) void OBSBasicTransform::onSceneChanged(QListWidgetItem *current, QListWidgetItem *)
{ {
if (!current) if (!current) {
return; return;
}
OBSScene scene = GetOBSRef<OBSScene>(current); OBSScene scene = GetOBSRef<OBSScene>(current);
this->setScene(scene); this->setScene(scene);
+10 -5
View File
@@ -48,9 +48,10 @@ void OBSBasicVCamConfig::OutputTypeChanged()
for (char **temp = scenes; *temp; temp++) { for (char **temp = scenes; *temp; temp++) {
list->addItem(*temp); list->addItem(*temp);
if (config.scene.compare(*temp) == 0) if (config.scene.compare(*temp) == 0) {
list->setCurrentIndex(list->count() - 1); list->setCurrentIndex(list->count() - 1);
} }
}
break; break;
} }
case VCamOutputType::SourceOutput: { case VCamOutputType::SourceOutput: {
@@ -59,8 +60,9 @@ void OBSBasicVCamConfig::OutputTypeChanged()
auto AddSource = [&](obs_source_t *source) { auto AddSource = [&](obs_source_t *source) {
auto name = obs_source_get_name(source); auto name = obs_source_get_name(source);
if (!(obs_source_get_output_flags(source) & OBS_SOURCE_VIDEO)) if (!(obs_source_get_output_flags(source) & OBS_SOURCE_VIDEO)) {
return; return;
}
sources.push_back(name); sources.push_back(name);
}; };
@@ -69,8 +71,9 @@ void OBSBasicVCamConfig::OutputTypeChanged()
obs_enum_sources( obs_enum_sources(
[](void *data, obs_source_t *source) { [](void *data, obs_source_t *source) {
auto &AddSource = *static_cast<AddSource_t *>(data); auto &AddSource = *static_cast<AddSource_t *>(data);
if (!obs_source_removed(source)) if (!obs_source_removed(source)) {
AddSource(source); AddSource(source);
}
return true; return true;
}, },
static_cast<void *>(&AddSource)); static_cast<void *>(&AddSource));
@@ -80,15 +83,17 @@ void OBSBasicVCamConfig::OutputTypeChanged()
for (auto &&source : sources) { for (auto &&source : sources) {
list->addItem(source.c_str()); list->addItem(source.c_str());
if (config.source == source) if (config.source == source) {
list->setCurrentIndex(list->count() - 1); list->setCurrentIndex(list->count() - 1);
} }
}
break; break;
} }
} }
if (!vcamActive) if (!vcamActive) {
return; return;
}
requireRestart = (activeType == VCamOutputType::ProgramView && type != VCamOutputType::ProgramView) || requireRestart = (activeType == VCamOutputType::ProgramView && type != VCamOutputType::ProgramView) ||
(activeType != VCamOutputType::ProgramView && type == VCamOutputType::ProgramView); (activeType != VCamOutputType::ProgramView && type == VCamOutputType::ProgramView);
+6 -3
View File
@@ -95,8 +95,9 @@ void OBSLogViewer::AddLine(int type, const QString &str)
QScrollBar *scroll = ui->textArea->verticalScrollBar(); QScrollBar *scroll = ui->textArea->verticalScrollBar();
bool bottomScrolled = scroll->value() >= scroll->maximum() - 10; bool bottomScrolled = scroll->value() >= scroll->maximum() - 10;
if (bottomScrolled) if (bottomScrolled) {
scroll->setValue(scroll->maximum()); scroll->setValue(scroll->maximum());
}
QTextDocument *doc = ui->textArea->document(); QTextDocument *doc = ui->textArea->document();
QTextCursor cursor(doc); QTextCursor cursor(doc);
@@ -106,15 +107,17 @@ void OBSLogViewer::AddLine(int type, const QString &str)
cursor.insertBlock(); cursor.insertBlock();
cursor.endEditBlock(); cursor.endEditBlock();
if (bottomScrolled) if (bottomScrolled) {
scroll->setValue(scroll->maximum()); scroll->setValue(scroll->maximum());
} }
}
void OBSLogViewer::on_openButton_clicked() void OBSLogViewer::on_openButton_clicked()
{ {
char logDir[512]; char logDir[512];
if (GetAppConfigPath(logDir, sizeof(logDir), "obs-studio/logs") <= 0) if (GetAppConfigPath(logDir, sizeof(logDir), "obs-studio/logs") <= 0) {
return; return;
}
const char *log = App()->GetCurrentLog(); const char *log = App()->GetCurrentLog();
+17 -10
View File
@@ -103,8 +103,9 @@ OBSRemux::OBSRemux(const char *path, QWidget *parent, bool autoRemux_)
bool OBSRemux::stopRemux() bool OBSRemux::stopRemux()
{ {
if (!worker->isWorking) if (!worker->isWorking) {
return true; return true;
}
// By locking the worker thread's mutex, we ensure that its // By locking the worker thread's mutex, we ensure that its
// update poll will be blocked as long as we're in here with // update poll will be blocked as long as we're in here with
@@ -190,9 +191,10 @@ void OBSRemux::dropEvent(QDropEvent *ev)
void OBSRemux::dragEnterEvent(QDragEnterEvent *ev) void OBSRemux::dragEnterEvent(QDragEnterEvent *ev)
{ {
if (ev->mimeData()->hasUrls() && !worker->isWorking) if (ev->mimeData()->hasUrls() && !worker->isWorking) {
ev->accept(); ev->accept();
} }
}
void OBSRemux::beginRemux() void OBSRemux::beginRemux()
{ {
@@ -208,15 +210,18 @@ void OBSRemux::beginRemux()
QString message = QTStr("Remux.FileExists"); QString message = QTStr("Remux.FileExists");
message += "\n\n"; message += "\n\n";
for (QFileInfo fileInfo : overwriteFiles) for (QFileInfo fileInfo : overwriteFiles) {
message += fileInfo.canonicalFilePath() + "\n"; message += fileInfo.canonicalFilePath() + "\n";
if (OBSMessageBox::question(this, QTStr("Remux.FileExistsTitle"), message) != QMessageBox::Yes)
proceedWithRemux = false;
} }
if (!proceedWithRemux) if (OBSMessageBox::question(this, QTStr("Remux.FileExistsTitle"), message) != QMessageBox::Yes) {
proceedWithRemux = false;
}
}
if (!proceedWithRemux) {
return; return;
}
// Set all jobs to "pending" first. // Set all jobs to "pending" first.
queueModel->beginProcessing(); queueModel->beginProcessing();
@@ -264,16 +269,18 @@ void OBSRemux::remuxNextEntry()
void OBSRemux::closeEvent(QCloseEvent *event) void OBSRemux::closeEvent(QCloseEvent *event)
{ {
if (!stopRemux()) if (!stopRemux()) {
event->ignore(); event->ignore();
else } else {
QDialog::closeEvent(event); QDialog::closeEvent(event);
} }
}
void OBSRemux::reject() void OBSRemux::reject()
{ {
if (!stopRemux()) if (!stopRemux()) {
return; return;
}
QDialog::reject(); QDialog::reject();
} }
+47 -26
View File
@@ -171,11 +171,13 @@ OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth, bool broadcast
connect(workerThread, &WorkerThread::failed, this, [&]() { connect(workerThread, &WorkerThread::failed, this, [&]() {
auto last_error = apiYouTube->GetLastError(); auto last_error = apiYouTube->GetLastError();
if (last_error.isEmpty()) if (last_error.isEmpty()) {
last_error = QTStr("YouTube.Actions.Error.YouTubeApi"); last_error = QTStr("YouTube.Actions.Error.YouTubeApi");
}
if (!apiYouTube->GetTranslatedError(last_error)) if (!apiYouTube->GetTranslatedError(last_error)) {
last_error = QTStr("YouTube.Actions.Error.Text").arg(last_error); last_error = QTStr("YouTube.Actions.Error.Text").arg(last_error);
}
ShowErrorDialog(this, last_error); ShowErrorDialog(this, last_error);
QDialog::reject(); QDialog::reject();
@@ -227,15 +229,17 @@ OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth, bool broadcast
}); });
ui->scrollAreaWidgetContents->layout()->addWidget(label); ui->scrollAreaWidgetContents->layout()->addWidget(label);
if (selectedBroadcast == broadcast) if (selectedBroadcast == broadcast) {
label->clicked(); label->clicked();
}
}); });
workerThread->start(); workerThread->start();
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
bool rememberSettings = config_get_bool(main->activeConfiguration, "YouTube", "RememberSettings"); bool rememberSettings = config_get_bool(main->activeConfiguration, "YouTube", "RememberSettings");
if (rememberSettings) if (rememberSettings) {
LoadSettings(); LoadSettings();
}
// Switch to events page and select readied broadcast once loaded // Switch to events page and select readied broadcast once loaded
if (broadcastReady) { if (broadcastReady) {
@@ -253,9 +257,10 @@ OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth, bool broadcast
void OBSYoutubeActions::showEvent(QShowEvent *event) void OBSYoutubeActions::showEvent(QShowEvent *event)
{ {
QDialog::showEvent(event); QDialog::showEvent(event);
if (thumbnailFile.isEmpty()) if (thumbnailFile.isEmpty()) {
ui->thumbnailPreview->setPixmap(GetPlaceholder().pixmap(QSize(16, 16))); ui->thumbnailPreview->setPixmap(GetPlaceholder().pixmap(QSize(16, 16)));
} }
}
OBSYoutubeActions::~OBSYoutubeActions() OBSYoutubeActions::~OBSYoutubeActions()
{ {
@@ -267,8 +272,9 @@ OBSYoutubeActions::~OBSYoutubeActions()
void WorkerThread::run() void WorkerThread::run()
{ {
if (!pending) if (!pending) {
return; return;
}
json11::Json broadcasts; json11::Json broadcasts;
for (QString broadcastStatus : {"active", "upcoming"}) { for (QString broadcastStatus : {"active", "upcoming"}) {
@@ -288,11 +294,13 @@ void WorkerThread::run()
QString stream_id = QString::fromStdString( QString stream_id = QString::fromStdString(
item["contentDetails"]["boundStreamId"].string_value()); item["contentDetails"]["boundStreamId"].string_value());
json11::Json stream; json11::Json stream;
if (!apiYouTube->FindStream(stream_id, stream)) if (!apiYouTube->FindStream(stream_id, stream)) {
continue; continue;
if (stream["status"]["streamStatus"] == "active") }
if (stream["status"]["streamStatus"] == "active") {
continue; continue;
} }
}
QString title = QString::fromStdString(item["snippet"]["title"].string_value()); QString title = QString::fromStdString(item["snippet"]["title"].string_value());
QString scheduledStartTime = QString scheduledStartTime =
@@ -317,11 +325,12 @@ void WorkerThread::run()
} }
auto nextPageToken = broadcasts["nextPageToken"].string_value(); auto nextPageToken = broadcasts["nextPageToken"].string_value();
if (nextPageToken.empty() || items.empty()) if (nextPageToken.empty() || items.empty()) {
break; break;
else { } else {
if (!pending) if (!pending) {
return; return;
}
if (!apiYouTube->GetBroadcastsList(broadcasts, QString::fromStdString(nextPageToken), if (!apiYouTube->GetBroadcastsList(broadcasts, QString::fromStdString(nextPageToken),
broadcastStatus)) { broadcastStatus)) {
emit failed(); emit failed();
@@ -420,8 +429,9 @@ bool OBSYoutubeActions::CreateEventAction(YoutubeApiWrappers *api, BroadcastDesc
} }
#ifdef YOUTUBE_ENABLED #ifdef YOUTUBE_ENABLED
if (OBSBasic::Get()->GetYouTubeAppDock()) if (OBSBasic::Get()->GetYouTubeAppDock()) {
OBSBasic::Get()->GetYouTubeAppDock()->BroadcastCreated(broadcast.id.toStdString().c_str()); OBSBasic::Get()->GetYouTubeAppDock()->BroadcastCreated(broadcast.id.toStdString().c_str());
}
#endif #endif
return true; return true;
@@ -461,14 +471,16 @@ bool OBSYoutubeActions::ChooseAnEventAction(YoutubeApiWrappers *api, StreamDescr
} }
} }
if (broadcastPrivacy != "private") if (broadcastPrivacy != "private") {
apiYouTube->SetChatId(selectedBroadcast); apiYouTube->SetChatId(selectedBroadcast);
else } else {
apiYouTube->ResetChat(); apiYouTube->ResetChat();
}
#ifdef YOUTUBE_ENABLED #ifdef YOUTUBE_ENABLED
if (OBSBasic::Get()->GetYouTubeAppDock()) if (OBSBasic::Get()->GetYouTubeAppDock()) {
OBSBasic::Get()->GetYouTubeAppDock()->BroadcastSelected(selectedBroadcast.toStdString().c_str()); OBSBasic::Get()->GetYouTubeAppDock()->BroadcastSelected(selectedBroadcast.toStdString().c_str());
}
#endif #endif
return true; return true;
@@ -503,8 +515,9 @@ void OBSYoutubeActions::InitBroadcast()
ui->checkScheduledLater->isChecked()); ui->checkScheduledLater->isChecked());
} else { } else {
success = this->ChooseAnEventAction(apiYouTube, stream); success = this->ChooseAnEventAction(apiYouTube, stream);
if (success) if (success) {
broadcast.id = this->selectedBroadcast; broadcast.id = this->selectedBroadcast;
}
}; };
QMetaObject::invokeMethod(&msgBox, "accept", Qt::QueuedConnection); QMetaObject::invokeMethod(&msgBox, "accept", Qt::QueuedConnection);
}; };
@@ -540,10 +553,12 @@ void OBSYoutubeActions::InitBroadcast()
} else { } else {
// Fail. // Fail.
auto last_error = apiYouTube->GetLastError(); auto last_error = apiYouTube->GetLastError();
if (last_error.isEmpty()) if (last_error.isEmpty()) {
last_error = QTStr("YouTube.Actions.Error.YouTubeApi"); last_error = QTStr("YouTube.Actions.Error.YouTubeApi");
if (!apiYouTube->GetTranslatedError(last_error)) }
if (!apiYouTube->GetTranslatedError(last_error)) {
last_error = QTStr("YouTube.Actions.Error.NoBroadcastCreated").arg(last_error); last_error = QTStr("YouTube.Actions.Error.NoBroadcastCreated").arg(last_error);
}
ShowErrorDialog(this, last_error); ShowErrorDialog(this, last_error);
} }
@@ -566,8 +581,9 @@ void OBSYoutubeActions::ReadyBroadcast()
ui->checkScheduledLater->isChecked(), true); ui->checkScheduledLater->isChecked(), true);
} else { } else {
success = this->ChooseAnEventAction(apiYouTube, stream); success = this->ChooseAnEventAction(apiYouTube, stream);
if (success) if (success) {
broadcast.id = this->selectedBroadcast; broadcast.id = this->selectedBroadcast;
}
}; };
QMetaObject::invokeMethod(&msgBox, "accept", Qt::QueuedConnection); QMetaObject::invokeMethod(&msgBox, "accept", Qt::QueuedConnection);
}; };
@@ -583,10 +599,12 @@ void OBSYoutubeActions::ReadyBroadcast()
} else { } else {
// Fail. // Fail.
auto last_error = apiYouTube->GetLastError(); auto last_error = apiYouTube->GetLastError();
if (last_error.isEmpty()) if (last_error.isEmpty()) {
last_error = QTStr("YouTube.Actions.Error.YouTubeApi"); last_error = QTStr("YouTube.Actions.Error.YouTubeApi");
if (!apiYouTube->GetTranslatedError(last_error)) }
if (!apiYouTube->GetTranslatedError(last_error)) {
last_error = QTStr("YouTube.Actions.Error.NoBroadcastCreated").arg(last_error); last_error = QTStr("YouTube.Actions.Error.NoBroadcastCreated").arg(last_error);
}
ShowErrorDialog(this, last_error); ShowErrorDialog(this, last_error);
} }
@@ -608,9 +626,10 @@ void OBSYoutubeActions::UiToBroadcast(BroadcastDescription &broadcast)
broadcast.schedul_for_later = ui->checkScheduledLater->isChecked(); broadcast.schedul_for_later = ui->checkScheduledLater->isChecked();
broadcast.projection = ui->check360Video->isChecked() ? "360" : "rectangular"; broadcast.projection = ui->check360Video->isChecked() ? "360" : "rectangular";
if (ui->checkRememberSettings->isChecked()) if (ui->checkRememberSettings->isChecked()) {
SaveSettings(broadcast); SaveSettings(broadcast);
} }
}
void OBSYoutubeActions::SaveSettings(BroadcastDescription &broadcast) void OBSYoutubeActions::SaveSettings(BroadcastDescription &broadcast)
{ {
@@ -657,10 +676,11 @@ void OBSYoutubeActions::LoadSettings()
ui->checkDVR->setChecked(dvr); ui->checkDVR->setChecked(dvr);
bool forKids = config_get_bool(main->activeConfiguration, "YouTube", "MadeForKids"); bool forKids = config_get_bool(main->activeConfiguration, "YouTube", "MadeForKids");
if (forKids) if (forKids) {
ui->yesMakeForKids->setChecked(true); ui->yesMakeForKids->setChecked(true);
else } else {
ui->notMakeForKids->setChecked(true); ui->notMakeForKids->setChecked(true);
}
bool schedLater = config_get_bool(main->activeConfiguration, "YouTube", "ScheduleForLater"); bool schedLater = config_get_bool(main->activeConfiguration, "YouTube", "ScheduleForLater");
ui->checkScheduledLater->setChecked(schedLater); ui->checkScheduledLater->setChecked(schedLater);
@@ -673,11 +693,12 @@ void OBSYoutubeActions::LoadSettings()
const char *projection = config_get_string(main->activeConfiguration, "YouTube", "Projection"); const char *projection = config_get_string(main->activeConfiguration, "YouTube", "Projection");
if (projection && *projection) { if (projection && *projection) {
if (strcmp(projection, "360") == 0) if (strcmp(projection, "360") == 0) {
ui->check360Video->setChecked(true); ui->check360Video->setChecked(true);
else } else {
ui->check360Video->setChecked(false); ui->check360Video->setChecked(false);
} }
}
const char *thumbFile = config_get_string(main->activeConfiguration, "YouTube", "ThumbnailFile"); const char *thumbFile = config_get_string(main->activeConfiguration, "YouTube", "ThumbnailFile");
if (thumbFile && *thumbFile) { if (thumbFile && *thumbFile) {
+24 -12
View File
@@ -41,8 +41,9 @@ YouTubeAppDock::YouTubeAppDock(const QString &title) : BrowserDock(title), dockB
bool YouTubeAppDock::IsYTServiceSelected() bool YouTubeAppDock::IsYTServiceSelected()
{ {
if (!cef_js_avail) if (!cef_js_avail) {
return false; return false;
}
obs_service_t *service_obj = OBSBasic::Get()->GetService(); obs_service_t *service_obj = OBSBasic::Get()->GetService();
OBSDataAutoRelease settings = obs_service_get_settings(service_obj); OBSDataAutoRelease settings = obs_service_get_settings(service_obj);
@@ -74,9 +75,10 @@ void YouTubeAppDock::SettingsUpdated(bool cleanup)
} }
} }
if (ytservice) if (ytservice) {
Update(); Update();
} }
}
std::string YouTubeAppDock::InitYTUserUrl() std::string YouTubeAppDock::InitYTUserUrl()
{ {
@@ -124,14 +126,17 @@ void YouTubeAppDock::AddYouTubeAppDock()
void YouTubeAppDock::CreateBrowserWidget(const std::string &url) void YouTubeAppDock::CreateBrowserWidget(const std::string &url)
{ {
if (dockBrowser) if (dockBrowser) {
delete dockBrowser; delete dockBrowser;
}
dockBrowser = cef->create_widget(this, url, panel_cookies); dockBrowser = cef->create_widget(this, url, panel_cookies);
if (!dockBrowser) if (!dockBrowser) {
return; return;
}
if (obs_browser_qcef_version() >= 1) if (obs_browser_qcef_version() >= 1) {
dockBrowser->allowAllPopups(true); dockBrowser->allowAllPopups(true);
}
this->SetWidget(dockBrowser); this->SetWidget(dockBrowser);
@@ -142,8 +147,9 @@ void YouTubeAppDock::CreateBrowserWidget(const std::string &url)
void YouTubeAppDock::SetVisibleYTAppDockInMenu(bool visible) void YouTubeAppDock::SetVisibleYTAppDockInMenu(bool visible)
{ {
if (visible && toggleViewAction()->isVisible()) if (visible && toggleViewAction()->isVisible()) {
return; return;
}
toggleViewAction()->setVisible(visible); toggleViewAction()->setVisible(visible);
this->setVisible(visible); this->setVisible(visible);
@@ -208,9 +214,10 @@ void YouTubeAppDock::IngestionStopped(const char *stream_id, streaming_mode_t mo
void YouTubeAppDock::showEvent(QShowEvent *) void YouTubeAppDock::showEvent(QShowEvent *)
{ {
if (!dockBrowser) if (!dockBrowser) {
Update(); Update();
} }
}
void YouTubeAppDock::closeEvent(QCloseEvent *event) void YouTubeAppDock::closeEvent(QCloseEvent *event)
{ {
@@ -220,8 +227,9 @@ void YouTubeAppDock::closeEvent(QCloseEvent *event)
void YouTubeAppDock::DispatchYTEvent(const char *event, const char *video_id, streaming_mode_t mode) void YouTubeAppDock::DispatchYTEvent(const char *event, const char *video_id, streaming_mode_t mode)
{ {
if (!dockBrowser) if (!dockBrowser) {
return; return;
}
// update channelId if empty: // update channelId if empty:
UpdateChannelId(); UpdateChannelId();
@@ -395,26 +403,30 @@ YoutubeApiWrappers *YouTubeAppDock::GetYTApi()
void YouTubeAppDock::CleanupYouTubeUrls() void YouTubeAppDock::CleanupYouTubeUrls()
{ {
if (!cef_js_avail) if (!cef_js_avail) {
return; return;
}
static constexpr const char *YOUTUBE_VIDEO_URL = "://studio.youtube.com/video/"; static constexpr const char *YOUTUBE_VIDEO_URL = "://studio.youtube.com/video/";
// remove legacy YouTube Browser Docks (once) // remove legacy YouTube Browser Docks (once)
bool youtube_cleanup_done = config_get_bool(App()->GetUserConfig(), "General", "YtDockCleanupDone"); bool youtube_cleanup_done = config_get_bool(App()->GetUserConfig(), "General", "YtDockCleanupDone");
if (youtube_cleanup_done) if (youtube_cleanup_done) {
return; return;
}
config_set_bool(App()->GetUserConfig(), "General", "YtDockCleanupDone", true); config_set_bool(App()->GetUserConfig(), "General", "YtDockCleanupDone", true);
const char *jsonStr = config_get_string(App()->GetUserConfig(), "BasicWindow", "ExtraBrowserDocks"); const char *jsonStr = config_get_string(App()->GetUserConfig(), "BasicWindow", "ExtraBrowserDocks");
if (!jsonStr) if (!jsonStr) {
return; return;
}
json array = json::parse(jsonStr); json array = json::parse(jsonStr);
if (!array.is_array()) if (!array.is_array()) {
return; return;
}
json save_array; json save_array;
std::string removedYTUrl; std::string removedYTUrl;
@@ -139,9 +139,10 @@ void ImporterEntryPathItemDelegate::handleBrowse(QWidget *container)
isSet = true; isSet = true;
} }
if (isSet) if (isSet) {
emit commitData(container); emit commitData(container);
} }
}
void ImporterEntryPathItemDelegate::handleClear(QWidget *container) void ImporterEntryPathItemDelegate::handleClear(QWidget *container)
{ {
+6 -4
View File
@@ -37,10 +37,11 @@ QVariant ImporterModel::data(const QModelIndex &index, int role) const
QVariant result = QVariant(); QVariant result = QVariant();
if (index.row() >= options.length()) { if (index.row() >= options.length()) {
if (role == ImporterEntryRole::CheckEmpty) if (role == ImporterEntryRole::CheckEmpty) {
result = true; result = true;
else } else {
return QVariant(); return QVariant();
}
} else if (role == Qt::DisplayRole) { } else if (role == Qt::DisplayRole) {
switch (index.column()) { switch (index.column()) {
case ImporterColumn::Path: case ImporterColumn::Path:
@@ -59,11 +60,12 @@ QVariant ImporterModel::data(const QModelIndex &index, int role) const
} else if (role == Qt::CheckStateRole) { } else if (role == Qt::CheckStateRole) {
switch (index.column()) { switch (index.column()) {
case ImporterColumn::Selected: case ImporterColumn::Selected:
if (options[index.row()].program != "") if (options[index.row()].program != "") {
result = options[index.row()].selected ? Qt::Checked : Qt::Unchecked; result = options[index.row()].selected ? Qt::Checked : Qt::Unchecked;
else } else {
result = Qt::Unchecked; result = Qt::Unchecked;
} }
}
} else if (role == ImporterEntryRole::CheckEmpty) { } else if (role == ImporterEntryRole::CheckEmpty) {
result = options[index.row()].empty; result = options[index.row()].empty;
} }
+6 -3
View File
@@ -77,8 +77,9 @@ OBSImporter::OBSImporter(QWidget *parent) : QDialog(parent), optionsModel(new Im
bool autoSearch = config_get_bool(App()->GetUserConfig(), "General", "AutomaticCollectionSearch"); bool autoSearch = config_get_bool(App()->GetUserConfig(), "General", "AutomaticCollectionSearch");
OBSImporterFiles f; OBSImporterFiles f;
if (autoSearch) if (autoSearch) {
f = ImportersFindFiles(); f = ImportersFindFiles();
}
for (size_t i = 0; i < f.size(); i++) { for (size_t i = 0; i < f.size(); i++) {
QString path = f[i].c_str(); QString path = f[i].c_str();
@@ -125,9 +126,10 @@ void OBSImporter::dropEvent(QDropEvent *ev)
void OBSImporter::dragEnterEvent(QDragEnterEvent *ev) void OBSImporter::dragEnterEvent(QDragEnterEvent *ev)
{ {
if (ev->mimeData()->hasUrls()) if (ev->mimeData()->hasUrls()) {
ev->accept(); ev->accept();
} }
}
void OBSImporter::browseImport() void OBSImporter::browseImport()
{ {
@@ -175,8 +177,9 @@ void OBSImporter::importCollections()
for (int i = 0; i < optionsModel->rowCount() - 1; i++) { for (int i = 0; i < optionsModel->rowCount() - 1; i++) {
int selected = optionsModel->index(i, ImporterColumn::Selected).data(Qt::CheckStateRole).value<int>(); int selected = optionsModel->index(i, ImporterColumn::Selected).data(Qt::CheckStateRole).value<int>();
if (selected == Qt::Unchecked) if (selected == Qt::Unchecked) {
continue; continue;
}
std::string pathStr = optionsModel->index(i, ImporterColumn::Path) std::string pathStr = optionsModel->index(i, ImporterColumn::Path)
.data(Qt::DisplayRole) .data(Qt::DisplayRole)
+42 -22
View File
@@ -26,9 +26,10 @@ static bool source_name_exists(const Json::array &sources, const string &name)
{ {
for (size_t i = 0; i < sources.size(); i++) { for (size_t i = 0; i < sources.size(); i++) {
Json source = sources[i]; Json source = sources[i];
if (name == source["name"].string_value()) if (name == source["name"].string_value()) {
return true; return true;
} }
}
return false; return false;
} }
@@ -208,8 +209,9 @@ static Json::object translate_source(const Json &in, const Json &sources)
Json browser = Json::parse(browser_dec, err); Json browser = Json::parse(browser_dec, err);
if (err != "") if (err != "") {
return Json::object{}; return Json::object{};
}
Json::object obj = browser.object_items(); Json::object obj = browser.object_items();
@@ -277,8 +279,9 @@ static void translate_sc(const Json &in, Json &out)
for (size_t i = 0; i < scenes.size(); i++) { for (size_t i = 0; i < scenes.size(); i++) {
Json in_scene = scenes[i]; Json in_scene = scenes[i];
if (first_name.empty()) if (first_name.empty()) {
first_name = in_scene["name"].string_value(); first_name = in_scene["name"].string_value();
}
Json::array items = Json::array{}; Json::array items = Json::array{};
@@ -294,9 +297,10 @@ static void translate_sc(const Json &in, Json &out)
items.push_back(out_item); items.push_back(out_item);
if (out_source.find("preexist") == out_source.end()) if (out_source.find("preexist") == out_source.end()) {
out_sources.push_back(out_source); out_sources.push_back(out_source);
} }
}
out_sources.push_back( out_sources.push_back(
Json::object{{"id", "scene"}, Json::object{{"id", "scene"},
@@ -341,12 +345,14 @@ static void create_data_item(Json::object &out, const string &line)
{ {
size_t end_pos = line.find(':') - 1; size_t end_pos = line.find(':') - 1;
if (end_pos == string::npos) if (end_pos == string::npos) {
return; return;
}
size_t start_pos = 0; size_t start_pos = 0;
while (line[start_pos] == ' ') while (line[start_pos] == ' ') {
start_pos++; start_pos++;
}
string name = line.substr(start_pos, end_pos - start_pos); string name = line.substr(start_pos, end_pos - start_pos);
const char *c_name = name.c_str(); const char *c_name = name.c_str();
@@ -404,12 +410,14 @@ static Json::array create_sources(Json::object &out, string &line, string &src)
while (!line.empty() && line[l_len - 1] != '}') { while (!line.empty() && line[l_len - 1] != '}') {
size_t end_pos = line.find(':'); size_t end_pos = line.find(':');
if (end_pos == string::npos) if (end_pos == string::npos) {
return Json::array{}; return Json::array{};
}
size_t start_pos = 0; size_t start_pos = 0;
while (line[start_pos] == ' ') while (line[start_pos] == ' ') {
start_pos++; start_pos++;
}
string name = line.substr(start_pos, end_pos - start_pos - 1); string name = line.substr(start_pos, end_pos - start_pos - 1);
@@ -423,8 +431,9 @@ static Json::array create_sources(Json::object &out, string &line, string &src)
l_len = line.size(); l_len = line.size();
} }
if (!out.empty()) if (!out.empty()) {
out["sources"] = res; out["sources"] = res;
}
return res; return res;
} }
@@ -433,12 +442,14 @@ static Json::object create_object(Json::object &out, string &line, string &src)
{ {
size_t end_pos = line.find(':'); size_t end_pos = line.find(':');
if (end_pos == string::npos) if (end_pos == string::npos) {
return Json::object{}; return Json::object{};
}
size_t start_pos = 0; size_t start_pos = 0;
while (line[start_pos] == ' ') while (line[start_pos] == ' ') {
start_pos++; start_pos++;
}
string name = line.substr(start_pos, end_pos - start_pos - 1); string name = line.substr(start_pos, end_pos - start_pos - 1);
@@ -450,22 +461,25 @@ static Json::object create_object(Json::object &out, string &line, string &src)
while (!line.empty() && line[l_len] != '}') { while (!line.empty() && line[l_len] != '}') {
start_pos = 0; start_pos = 0;
while (line[start_pos] == ' ') while (line[start_pos] == ' ') {
start_pos++; start_pos++;
}
if (line.substr(start_pos, 7) == "sources") if (line.substr(start_pos, 7) == "sources") {
create_sources(res, line, src); create_sources(res, line, src);
else if (line[l_len] == '{') } else if (line[l_len] == '{') {
create_object(res, line, src); create_object(res, line, src);
else } else {
create_data_item(res, line); create_data_item(res, line);
}
line = ReadLine(src); line = ReadLine(src);
l_len = line.size() - 1; l_len = line.size() - 1;
} }
if (!out.empty()) if (!out.empty()) {
out[name] = res; out[name] = res;
}
return res; return res;
} }
@@ -478,11 +492,13 @@ string ClassicImporter::Name(const string &path)
int ClassicImporter::ImportScenes(const string &path, string &name, Json &res) int ClassicImporter::ImportScenes(const string &path, string &name, Json &res)
{ {
BPtr<char> file_data = os_quick_read_utf8_file(path.c_str()); BPtr<char> file_data = os_quick_read_utf8_file(path.c_str());
if (!file_data) if (!file_data) {
return IMPORTER_FILE_WONT_OPEN; return IMPORTER_FILE_WONT_OPEN;
}
if (name.empty()) if (name.empty()) {
name = GetFilenameFromPath(path); name = GetFilenameFromPath(path);
}
Json::object data = Json::object{}; Json::object data = Json::object{};
data["name"] = name; data["name"] = name;
@@ -514,13 +530,15 @@ bool ClassicImporter::Check(const string &path)
{ {
BPtr<char> file_data = os_quick_read_utf8_file(path.c_str()); BPtr<char> file_data = os_quick_read_utf8_file(path.c_str());
if (!file_data) if (!file_data) {
return false; return false;
}
bool check = false; bool check = false;
if (strncmp(file_data, "scenes : {\r\n", 12) == 0) if (strncmp(file_data, "scenes : {\r\n", 12) == 0) {
check = true; check = true;
}
return check; return check;
} }
@@ -532,14 +550,16 @@ OBSImporterFiles ClassicImporter::FindFiles()
#ifdef _WIN32 #ifdef _WIN32
char dst[512]; char dst[512];
int found = os_get_config_path(dst, 512, "OBS\\sceneCollection\\"); int found = os_get_config_path(dst, 512, "OBS\\sceneCollection\\");
if (found == -1) if (found == -1) {
return res; return res;
}
os_dir_t *dir = os_opendir(dst); os_dir_t *dir = os_opendir(dst);
struct os_dirent *ent; struct os_dirent *ent;
while ((ent = os_readdir(dir)) != NULL) { while ((ent = os_readdir(dir)) != NULL) {
if (ent->directory || *ent->d_name == '.') if (ent->directory || *ent->d_name == '.') {
continue; continue;
}
string name = ent->d_name; string name = ent->d_name;
size_t pos = name.find(".xconfig"); size_t pos = name.find(".xconfig");
+10 -5
View File
@@ -103,8 +103,9 @@ static inline std::string GetFilenameFromPath(const std::string &path)
{ {
#ifdef _WIN32 #ifdef _WIN32
size_t pos = path.find_last_of('\\'); size_t pos = path.find_last_of('\\');
if (pos == -1 || pos < path.find_last_of('/')) if (pos == -1 || pos < path.find_last_of('/')) {
pos = path.find_last_of('/'); pos = path.find_last_of('/');
}
#else #else
size_t pos = path.find_last_of('/'); size_t pos = path.find_last_of('/');
#endif #endif
@@ -121,8 +122,9 @@ static inline std::string GetFolderFromPath(const std::string &path)
{ {
#ifdef _WIN32 #ifdef _WIN32
size_t pos = path.find_last_of('\\'); size_t pos = path.find_last_of('\\');
if (pos == -1 || pos < path.find_last_of('/')) if (pos == -1 || pos < path.find_last_of('/')) {
pos = path.find_last_of('/'); pos = path.find_last_of('/');
}
#else #else
size_t pos = path.find_last_of('/'); size_t pos = path.find_last_of('/');
#endif #endif
@@ -147,14 +149,17 @@ static inline std::string ReadLine(std::string &str)
size_t pos = str.find('\n'); size_t pos = str.find('\n');
if (pos == std::string::npos) if (pos == std::string::npos) {
pos = str.find(EOF); pos = str.find(EOF);
}
if (pos == std::string::npos) if (pos == std::string::npos) {
pos = str.find('\0'); pos = str.find('\0');
}
if (pos == std::string::npos) if (pos == std::string::npos) {
return ""; return "";
}
std::string res = str.substr(0, pos); std::string res = str.substr(0, pos);
str = str.substr(pos + 1); str = str.substr(pos + 1);
+24 -12
View File
@@ -114,9 +114,10 @@ static bool source_name_exists(const Json::array &sources, const string &name)
Json item = sources[i]; Json item = sources[i];
string source_name = item["name"].string_value(); string source_name = item["name"].string_value();
if (source_name == name) if (source_name == name) {
return true; return true;
} }
}
return false; return false;
} }
@@ -127,9 +128,10 @@ static string get_source_name_from_id(const Json &root, const Json::array &sourc
Json item = sources[i]; Json item = sources[i];
string source_id = item["sl_id"].string_value(); string source_id = item["sl_id"].string_value();
if (source_id == id) if (source_id == id) {
return item["name"].string_value(); return item["name"].string_value();
} }
}
Json::array scene_arr = root["scenes"]["items"].array_items(); Json::array scene_arr = root["scenes"]["items"].array_items();
@@ -143,8 +145,9 @@ static string get_source_name_from_id(const Json &root, const Json::array &sourc
int copy = 1; int copy = 1;
string out_name = name; string out_name = name;
while (source_name_exists(sources, out_name)) while (source_name_exists(sources, out_name)) {
out_name = name + "(" + to_string(copy++) + ")"; out_name = name + "(" + to_string(copy++) + ")";
}
return out_name; return out_name;
} }
@@ -169,8 +172,9 @@ static void get_hotkey_bindings(Json::object &out_hotkeys, const Json &in_hotkey
string key = translate_key(binding["key"].string_value()); string key = translate_key(binding["key"].string_value());
if (key == "IGNORE") if (key == "IGNORE") {
continue; continue;
}
out_hotkey.push_back(Json::object{{"control", modifiers["ctrl"]}, out_hotkey.push_back(Json::object{{"control", modifiers["ctrl"]},
{"shift", modifiers["shift"]}, {"shift", modifiers["shift"]},
@@ -285,8 +289,9 @@ static int attempt_import(const Json &root, const string &name, Json &res)
int copy = 1; int copy = 1;
string out_name = name; string out_name = name;
while (source_name_exists(out_sources, out_name)) while (source_name_exists(out_sources, out_name)) {
out_name = name + "(" + to_string(copy++) + ")"; out_name = name + "(" + to_string(copy++) + ")";
}
string sl_id = source["id"].string_value(); string sl_id = source["id"].string_value();
@@ -336,11 +341,13 @@ static int attempt_import(const Json &root, const string &name, Json &res)
int copy = 1; int copy = 1;
string out_name = name; string out_name = name;
while (source_name_exists(out_sources, out_name)) while (source_name_exists(out_sources, out_name)) {
out_name = name + "(" + to_string(copy++) + ")"; out_name = name + "(" + to_string(copy++) + ")";
}
if (scene_name.empty()) if (scene_name.empty()) {
scene_name = out_name; scene_name = out_name;
}
string sl_id = scene["id"].string_value(); string sl_id = scene["id"].string_value();
@@ -368,8 +375,9 @@ static int attempt_import(const Json &root, const string &name, Json &res)
string name = transition["name"].string_value(); string name = transition["name"].string_value();
string id = transition["id"].string_value(); string id = transition["id"].string_value();
if (id == t_id) if (id == t_id) {
transition_name = name; transition_name = name;
}
out_transitions.push_back(Json::object{{"id", transition["type"]}, out_transitions.push_back(Json::object{{"id", transition["type"]},
{"settings", in_settings}, {"settings", in_settings},
@@ -436,8 +444,9 @@ int SLImporter::ImportScenes(const string &path, string &name, Json &res)
std::string err; std::string err;
Json data = Json::parse(file_data, err); Json data = Json::parse(file_data, err);
if (err != "") if (err != "") {
return IMPORTER_ERROR_DURING_CONVERSION; return IMPORTER_ERROR_DURING_CONVERSION;
}
string node_type = data["nodeType"].string_value(); string node_type = data["nodeType"].string_value();
@@ -473,10 +482,11 @@ bool SLImporter::Check(const string &path)
if (!root.is_null()) { if (!root.is_null()) {
string node_type = root["nodeType"].string_value(); string node_type = root["nodeType"].string_value();
if (node_type == "RootNode") if (node_type == "RootNode") {
check = true; check = true;
} }
} }
}
return check; return check;
} }
@@ -489,16 +499,18 @@ OBSImporterFiles SLImporter::FindFiles()
int found = os_get_config_path(dst, 512, "slobs-client/SceneCollections/"); int found = os_get_config_path(dst, 512, "slobs-client/SceneCollections/");
if (found == -1) if (found == -1) {
return res; return res;
}
os_dir_t *dir = os_opendir(dst); os_dir_t *dir = os_opendir(dst);
struct os_dirent *ent; struct os_dirent *ent;
while ((ent = os_readdir(dir)) != NULL) { while ((ent = os_readdir(dir)) != NULL) {
string name = ent->d_name; string name = ent->d_name;
if (ent->directory || name[0] == '.' || name == "manifest.json") if (ent->directory || name[0] == '.' || name == "manifest.json") {
continue; continue;
}
size_t pos = name.find_last_of(".json"); size_t pos = name.find_last_of(".json");
size_t end_pos = name.size() - 1; size_t end_pos = name.size() - 1;
+29 -15
View File
@@ -151,14 +151,17 @@ static string CheckPath(const string &path, const string &rootDir)
*absPath = 0; *absPath = 0;
size_t len = os_get_abs_path((rootDir + path).c_str(), absPath, sizeof(absPath)); size_t len = os_get_abs_path((rootDir + path).c_str(), absPath, sizeof(absPath));
if (len == 0) if (len == 0) {
return path; return path;
}
if (strstr(absPath, root) != absPath) if (strstr(absPath, root) != absPath) {
return path; return path;
}
if (*(absPath + rootLen) != QDir::separator().toLatin1()) if (*(absPath + rootLen) != QDir::separator().toLatin1()) {
return path; return path;
}
return absPath; return absPath;
} }
@@ -172,8 +175,9 @@ void TranslatePaths(Json &res, const string &rootDir)
Json val = it->second; Json val = it->second;
if (val.is_string()) { if (val.is_string()) {
if (val.string_value().rfind("./", 0) != 0) if (val.string_value().rfind("./", 0) != 0) {
continue; continue;
}
out[it->first] = CheckPath(val.string_value(), rootDir); out[it->first] = CheckPath(val.string_value(), rootDir);
} else if (val.is_array() || val.is_object()) { } else if (val.is_array() || val.is_object()) {
@@ -190,8 +194,9 @@ void TranslatePaths(Json &res, const string &rootDir)
Json val = out[i]; Json val = out[i];
if (val.is_string()) { if (val.is_string()) {
if (val.string_value().rfind("./", 0) != 0) if (val.string_value().rfind("./", 0) != 0) {
continue; continue;
}
out[i] = CheckPath(val.string_value(), rootDir); out[i] = CheckPath(val.string_value(), rootDir);
} else if (val.is_array() || val.is_object()) { } else if (val.is_array() || val.is_object()) {
@@ -210,20 +215,25 @@ bool StudioImporter::Check(const string &path)
string err; string err;
Json collection = Json::parse(file_data, err); Json collection = Json::parse(file_data, err);
if (err != "") if (err != "") {
return false; return false;
}
if (collection.is_null()) if (collection.is_null()) {
return false; return false;
}
if (collection["sources"].is_null()) if (collection["sources"].is_null()) {
return false; return false;
}
if (collection["name"].is_null()) if (collection["name"].is_null()) {
return false; return false;
}
if (collection["current_scene"].is_null()) if (collection["current_scene"].is_null()) {
return false; return false;
}
return true; return true;
} }
@@ -242,18 +252,21 @@ string StudioImporter::Name(const string &path)
int StudioImporter::ImportScenes(const string &path, string &name, Json &res) int StudioImporter::ImportScenes(const string &path, string &name, Json &res)
{ {
if (!os_file_exists(path.c_str())) if (!os_file_exists(path.c_str())) {
return IMPORTER_FILE_NOT_FOUND; return IMPORTER_FILE_NOT_FOUND;
}
if (!Check(path.c_str())) if (!Check(path.c_str())) {
return IMPORTER_FILE_NOT_RECOGNISED; return IMPORTER_FILE_NOT_RECOGNISED;
}
BPtr<char> file_data = os_quick_read_utf8_file(path.c_str()); BPtr<char> file_data = os_quick_read_utf8_file(path.c_str());
string err; string err;
Json d = Json::parse(file_data, err); Json d = Json::parse(file_data, err);
if (err != "") if (err != "") {
return IMPORTER_ERROR_DURING_CONVERSION; return IMPORTER_ERROR_DURING_CONVERSION;
}
QDir dir(path.c_str()); QDir dir(path.c_str());
@@ -262,10 +275,11 @@ int StudioImporter::ImportScenes(const string &path, string &name, Json &res)
Json::object obj = d.object_items(); Json::object obj = d.object_items();
if (name != "") if (name != "") {
obj["name"] = name; obj["name"] = name;
else } else {
obj["name"] = "OBS Studio Import"; obj["name"] = "OBS Studio Import";
}
res = obj; res = obj;
+44 -24
View File
@@ -27,16 +27,18 @@ static int hex_string_to_int(string str)
{ {
int res = 0; int res = 0;
if (str[0] == '#') if (str[0] == '#') {
str = str.substr(1); str = str.substr(1);
}
for (size_t i = 0, l = str.size(); i < l; i++) { for (size_t i = 0, l = str.size(); i < l; i++) {
res *= 16; res *= 16;
if (str[0] >= '0' && str[0] <= '9') if (str[0] >= '0' && str[0] <= '9') {
res += str[0] - '0'; res += str[0] - '0';
else } else {
res += str[0] - 'A' + 10; res += str[0] - 'A' + 10;
}
str = str.substr(1); str = str.substr(1);
} }
@@ -53,24 +55,27 @@ static Json::object parse_text(QString &config)
string err; string err;
Json data = Json::parse(config.toStdString(), err); Json data = Json::parse(config.toStdString(), err);
if (err != "") if (err != "") {
return Json::object{}; return Json::object{};
}
string outline = data["outline"].string_value(); string outline = data["outline"].string_value();
int out = 0; int out = 0;
if (outline == "thick") if (outline == "thick") {
out = 20; out = 20;
else if (outline == "thicker") } else if (outline == "thicker") {
out = 40; out = 40;
else if (outline == "thinner") } else if (outline == "thinner") {
out = 5; out = 5;
else if (outline == "thin") } else if (outline == "thin") {
out = 10; out = 10;
}
string valign = data["vertAlign"].string_value(); string valign = data["vertAlign"].string_value();
if (valign == "middle") if (valign == "middle") {
valign = "center"; valign = "center";
}
Json font = Json::object{{"face", data["fontStyle"]}, {"size", 200}}; Json font = Json::object{{"face", data["fontStyle"]}, {"size", 200}};
@@ -96,8 +101,9 @@ static Json::array parse_playlist(QString &playlist)
out.push_back(Json::object{{"value", path.toStdString()}}); out.push_back(Json::object{{"value", path.toStdString()}});
int next = playlist.indexOf('|'); int next = playlist.indexOf('|');
if (next == -1) if (next == -1) {
break; break;
}
playlist = playlist.mid(next + 1); playlist = playlist.mid(next + 1);
} }
@@ -114,8 +120,9 @@ static void parse_media_types(QDomNamedNodeMap &attr, Json::object &source, Json
settings["playlist"] = parse_playlist(playlist); settings["playlist"] = parse_playlist(playlist);
QString end_op = attr.namedItem("OpWhenFinished").nodeValue(); QString end_op = attr.namedItem("OpWhenFinished").nodeValue();
if (end_op == "2") if (end_op == "2") {
settings["loop"] = true; settings["loop"] = true;
}
} else { } else {
QString url = attr.namedItem("item").nodeValue(); QString url = attr.namedItem("item").nodeValue();
int sep = url.indexOf("://"); int sep = url.indexOf("://");
@@ -149,22 +156,25 @@ static void parse_media_types(QDomNamedNodeMap &attr, Json::object &source, Json
static Json::object parse_slideshow(QString &config) static Json::object parse_slideshow(QString &config)
{ {
int start = config.indexOf("images\":["); int start = config.indexOf("images\":[");
if (start == -1) if (start == -1) {
return Json::object{}; return Json::object{};
}
config = config.mid(start + 8); config = config.mid(start + 8);
config.replace("\\\\", "/"); config.replace("\\\\", "/");
int end = config.indexOf(']'); int end = config.indexOf(']');
if (end == -1) if (end == -1) {
return Json::object{}; return Json::object{};
}
string arr = config.left(end + 1).toStdString(); string arr = config.left(end + 1).toStdString();
string err; string err;
Json::array files = Json::parse(arr, err).array_items(); Json::array files = Json::parse(arr, err).array_items();
if (err != "") if (err != "") {
return Json::object{}; return Json::object{};
}
Json::array files_out = Json::array{}; Json::array files_out = Json::array{};
@@ -178,8 +188,9 @@ static Json::object parse_slideshow(QString &config)
Json opt = Json::parse(options.toStdString(), err); Json opt = Json::parse(options.toStdString(), err);
if (err != "") if (err != "") {
return Json::object{}; return Json::object{};
}
return Json::object{{"randomize", opt["random"]}, return Json::object{{"randomize", opt["random"]},
{"slide_time", opt["delay"].number_value() * 1000 + 700}, {"slide_time", opt["delay"].number_value() * 1000 + 700},
@@ -189,9 +200,10 @@ static Json::object parse_slideshow(QString &config)
static bool source_name_exists(const string &name, const Json::array &sources) static bool source_name_exists(const string &name, const Json::array &sources)
{ {
for (size_t i = 0; i < sources.size(); i++) { for (size_t i = 0; i < sources.size(); i++) {
if (sources.at(i)["name"].string_value() == name) if (sources.at(i)["name"].string_value() == name) {
return true; return true;
} }
}
return false; return false;
} }
@@ -199,9 +211,10 @@ static bool source_name_exists(const string &name, const Json::array &sources)
static Json get_source_with_id(const string &src_id, const Json::array &sources) static Json get_source_with_id(const string &src_id, const Json::array &sources)
{ {
for (size_t i = 0; i < sources.size(); i++) { for (size_t i = 0; i < sources.size(); i++) {
if (sources.at(i)["src_id"].string_value() == src_id) if (sources.at(i)["src_id"].string_value() == src_id) {
return sources.at(i); return sources.at(i);
} }
}
return nullptr; return nullptr;
} }
@@ -227,8 +240,9 @@ static void parse_items(QDomNode &item, Json::array &items, Json::array &sources
} }
name = attr.namedItem("cname").nodeValue().toStdString(); name = attr.namedItem("cname").nodeValue().toStdString();
if (name.empty() || name[0] == '\0') if (name.empty() || name[0] == '\0') {
name = attr.namedItem("name").nodeValue().toStdString(); name = attr.namedItem("name").nodeValue().toStdString();
}
temp_name = name; temp_name = name;
while (source_name_exists(temp_name, sources)) { while (source_name_exists(temp_name, sources)) {
@@ -394,8 +408,9 @@ static Json::object parse_scenes(QDomElement &scenes)
QString name = attr.namedItem("name").nodeValue(); QString name = attr.namedItem("name").nodeValue();
QString id = attr.namedItem("id").nodeValue(); QString id = attr.namedItem("id").nodeValue();
if (first.isEmpty()) if (first.isEmpty()) {
first = name; first = name;
}
Json out = Json::object{{"id", "scene"}, Json out = Json::object{{"id", "scene"},
{"name", name.toStdString().c_str()}, {"name", name.toStdString().c_str()},
@@ -429,13 +444,15 @@ static Json::object parse_scenes(QDomElement &scenes)
int XSplitImporter::ImportScenes(const string &path, string &name, json11::Json &res) int XSplitImporter::ImportScenes(const string &path, string &name, json11::Json &res)
{ {
if (name == "") if (name == "") {
name = "XSplit Import"; name = "XSplit Import";
}
BPtr<char> file_data = os_quick_read_utf8_file(path.c_str()); BPtr<char> file_data = os_quick_read_utf8_file(path.c_str());
if (!file_data) if (!file_data) {
return IMPORTER_FILE_WONT_OPEN; return IMPORTER_FILE_WONT_OPEN;
}
QDomDocument doc; QDomDocument doc;
doc.setContent(QString(file_data)); doc.setContent(QString(file_data));
@@ -461,8 +478,9 @@ bool XSplitImporter::Check(const string &path)
BPtr<char> file_data = os_quick_read_utf8_file(path.c_str()); BPtr<char> file_data = os_quick_read_utf8_file(path.c_str());
if (!file_data) if (!file_data) {
return false; return false;
}
string pos = file_data.Get(); string pos = file_data.Get();
@@ -488,8 +506,9 @@ OBSImporterFiles XSplitImporter::FindFiles()
char dst[512]; char dst[512];
int found = os_get_program_data_path(dst, 512, "SplitMediaLabs\\XSplit\\Presentation2.0\\"); int found = os_get_program_data_path(dst, 512, "SplitMediaLabs\\XSplit\\Presentation2.0\\");
if (found == -1) if (found == -1) {
return res; return res;
}
os_dir_t *dir = os_opendir(dst); os_dir_t *dir = os_opendir(dst);
struct os_dirent *ent; struct os_dirent *ent;
@@ -497,8 +516,9 @@ OBSImporterFiles XSplitImporter::FindFiles()
while ((ent = os_readdir(dir)) != NULL) { while ((ent = os_readdir(dir)) != NULL) {
string name = ent->d_name; string name = ent->d_name;
if (ent->directory || name[0] == '.') if (ent->directory || name[0] == '.') {
continue; continue;
}
if (name == "Placements.bpres") { if (name == "Placements.bpres") {
string str = dst + name; string str = dst + name;
+2 -1
View File
@@ -54,8 +54,9 @@ void Auth::Load()
{ {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
const char *typeStr = config_get_string(main->Config(), "Auth", "Type"); const char *typeStr = config_get_string(main->Config(), "Auth", "Type");
if (!typeStr) if (!typeStr) {
typeStr = ""; typeStr = "";
}
main->auth = Create(typeStr); main->auth = Create(typeStr);
if (main->auth) { if (main->auth) {
+2 -1
View File
@@ -72,10 +72,11 @@ void AuthListener::NewConnection()
if (match.hasMatch()) { if (match.hasMatch()) {
if (state == match.captured("state")) { if (state == match.captured("state")) {
match = re_code.match(redirect); match = re_code.match(redirect);
if (!match.hasMatch()) if (!match.hasMatch()) {
blog(LOG_DEBUG, "no 'code' " blog(LOG_DEBUG, "no 'code' "
"in server " "in server "
"redirect"); "redirect");
}
code = match.captured("code"); code = match.captured("code");
} else { } else {
+19 -10
View File
@@ -73,10 +73,12 @@ bool OAuth::LoadInternal()
bool OAuth::TokenExpired() bool OAuth::TokenExpired()
{ {
if (token.empty()) if (token.empty()) {
return true; return true;
if ((uint64_t)time(nullptr) > expire_time - 5) }
if ((uint64_t)time(nullptr) > expire_time - 5) {
return true; return true;
}
return false; return false;
} }
@@ -142,12 +144,14 @@ try {
}; };
ExecThreadedWithoutBlocking(func, QTStr("Auth.Authing.Title"), QTStr("Auth.Authing.Text").arg(service())); ExecThreadedWithoutBlocking(func, QTStr("Auth.Authing.Title"), QTStr("Auth.Authing.Text").arg(service()));
if (!success || output.empty()) if (!success || output.empty()) {
throw ErrorInfo("Failed to get token from remote", error); throw ErrorInfo("Failed to get token from remote", error);
}
Json json = Json::parse(output, error); Json json = Json::parse(output, error);
if (!error.empty()) if (!error.empty()) {
throw ErrorInfo("Failed to parse json", error); throw ErrorInfo("Failed to parse json", error);
}
/* -------------------------- */ /* -------------------------- */
/* error handling */ /* error handling */
@@ -158,23 +162,26 @@ try {
return true; return true;
} }
} }
if (!error.empty()) if (!error.empty()) {
throw ErrorInfo(error, json["error_description"].string_value()); throw ErrorInfo(error, json["error_description"].string_value());
}
/* -------------------------- */ /* -------------------------- */
/* success! */ /* success! */
expire_time = (uint64_t)time(nullptr) + json["expires_in"].int_value(); expire_time = (uint64_t)time(nullptr) + json["expires_in"].int_value();
token = json["access_token"].string_value(); token = json["access_token"].string_value();
if (token.empty()) if (token.empty()) {
throw ErrorInfo("Failed to get token from remote", error); throw ErrorInfo("Failed to get token from remote", error);
}
if (!auth_code.empty()) { if (!auth_code.empty()) {
refresh_token = json["refresh_token"].string_value(); refresh_token = json["refresh_token"].string_value();
if (refresh_token.empty()) if (refresh_token.empty()) {
throw ErrorInfo("Failed to get refresh token from " throw ErrorInfo("Failed to get refresh token from "
"remote", "remote",
error); error);
}
currentScopeVer = scope_ver; currentScopeVer = scope_ver;
} }
@@ -195,8 +202,9 @@ try {
void OAuthStreamKey::OnStreamConfig() void OAuthStreamKey::OnStreamConfig()
{ {
if (key_.empty()) if (key_.empty()) {
return; return;
}
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
obs_service_t *service = main->GetService(); obs_service_t *service = main->GetService();
@@ -205,10 +213,11 @@ void OAuthStreamKey::OnStreamConfig()
bool bwtest = obs_data_get_bool(settings, "bwtest"); bool bwtest = obs_data_get_bool(settings, "bwtest");
if (bwtest && strcmp(this->service(), "Twitch") == 0) if (bwtest && strcmp(this->service(), "Twitch") == 0) {
obs_data_set_string(settings, "key", (key_ + "?bandwidthtest=true").c_str()); obs_data_set_string(settings, "key", (key_ + "?bandwidthtest=true").c_str());
else } else {
obs_data_set_string(settings, "key", key_.c_str()); obs_data_set_string(settings, "key", key_.c_str());
}
obs_service_update(service, settings); obs_service_update(service, settings);
} }
+22 -11
View File
@@ -34,8 +34,9 @@ RestreamAuth::RestreamAuth(const Def &d) : OAuthStreamKey(d) {}
RestreamAuth::~RestreamAuth() RestreamAuth::~RestreamAuth()
{ {
if (!uiLoaded) if (!uiLoaded) {
return; return;
}
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
@@ -49,12 +50,15 @@ try {
std::string client_id = RESTREAM_CLIENTID; std::string client_id = RESTREAM_CLIENTID;
deobfuscate_str(&client_id[0], RESTREAM_HASH); deobfuscate_str(&client_id[0], RESTREAM_HASH);
if (!GetToken(RESTREAM_TOKEN_URL, client_id, RESTREAM_SCOPE_VERSION)) if (!GetToken(RESTREAM_TOKEN_URL, client_id, RESTREAM_SCOPE_VERSION)) {
return false; return false;
if (token.empty()) }
if (token.empty()) {
return false; return false;
if (!key_.empty()) }
if (!key_.empty()) {
return true; return true;
}
std::string auth; std::string auth;
auth += "Authorization: Bearer "; auth += "Authorization: Bearer ";
@@ -76,16 +80,19 @@ try {
ExecThreadedWithoutBlocking(func, QTStr("Auth.LoadingChannel.Title"), ExecThreadedWithoutBlocking(func, QTStr("Auth.LoadingChannel.Title"),
QTStr("Auth.LoadingChannel.Text").arg(service())); QTStr("Auth.LoadingChannel.Text").arg(service()));
if (!success || output.empty()) if (!success || output.empty()) {
throw ErrorInfo("Failed to get stream key from remote", error); throw ErrorInfo("Failed to get stream key from remote", error);
}
json = Json::parse(output, error); json = Json::parse(output, error);
if (!error.empty()) if (!error.empty()) {
throw ErrorInfo("Failed to parse json", error); throw ErrorInfo("Failed to parse json", error);
}
error = json["error"].string_value(); error = json["error"].string_value();
if (!error.empty()) if (!error.empty()) {
throw ErrorInfo(error, json["error_description"].string_value()); throw ErrorInfo(error, json["error_description"].string_value());
}
key_ = json["streamKey"].string_value(); key_ = json["streamKey"].string_value();
@@ -121,12 +128,15 @@ bool RestreamAuth::LoadInternal()
void RestreamAuth::LoadUI() void RestreamAuth::LoadUI()
{ {
if (!cef) if (!cef) {
return; return;
if (uiLoaded) }
if (uiLoaded) {
return; return;
if (!GetChannelInfo()) }
if (!GetChannelInfo()) {
return; return;
}
OBSBasic::InitBrowserPanelSafeBlock(); OBSBasic::InitBrowserPanelSafeBlock();
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
@@ -266,8 +276,9 @@ static void DeleteCookies()
void RegisterRestreamAuth() void RegisterRestreamAuth()
{ {
#if !defined(__APPLE__) && !defined(_WIN32) #if !defined(__APPLE__) && !defined(_WIN32)
if (QApplication::platformName().contains("wayland")) if (QApplication::platformName().contains("wayland")) {
return; return;
}
#endif #endif
OAuth::RegisterOAuth(restreamDef, CreateRestreamAuth, RestreamAuth::Login, DeleteCookies); OAuth::RegisterOAuth(restreamDef, CreateRestreamAuth, RestreamAuth::Login, DeleteCookies);
+42 -21
View File
@@ -33,8 +33,9 @@ static Auth::Def twitchDef = {"Twitch", Auth::Type::OAuth_StreamKey};
TwitchAuth::TwitchAuth(const Def &d) : OAuthStreamKey(d) TwitchAuth::TwitchAuth(const Def &d) : OAuthStreamKey(d)
{ {
if (!cef) if (!cef) {
return; return;
}
cef->add_popup_whitelist_url("https://twitch.tv/popout/frankerfacez/chat?ffz-settings", this); cef->add_popup_whitelist_url("https://twitch.tv/popout/frankerfacez/chat?ffz-settings", this);
@@ -48,8 +49,9 @@ TwitchAuth::TwitchAuth(const Def &d) : OAuthStreamKey(d)
TwitchAuth::~TwitchAuth() TwitchAuth::~TwitchAuth()
{ {
if (!uiLoaded) if (!uiLoaded) {
return; return;
}
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
@@ -95,16 +97,19 @@ bool TwitchAuth::MakeApiRequest(const char *path, Json &json_out)
return false; return false;
} }
if (!success || output.empty()) if (!success || output.empty()) {
throw ErrorInfo("Failed to get text from remote", error); throw ErrorInfo("Failed to get text from remote", error);
}
json_out = Json::parse(output, error); json_out = Json::parse(output, error);
if (!error.empty()) if (!error.empty()) {
throw ErrorInfo("Failed to parse json", error); throw ErrorInfo("Failed to parse json", error);
}
error = json_out["error"].string_value(); error = json_out["error"].string_value();
if (!error.empty()) if (!error.empty()) {
throw ErrorInfo(error, json_out["message"].string_value()); throw ErrorInfo(error, json_out["message"].string_value());
}
return true; return true;
} }
@@ -114,25 +119,30 @@ try {
std::string client_id = TWITCH_CLIENTID; std::string client_id = TWITCH_CLIENTID;
deobfuscate_str(&client_id[0], TWITCH_HASH); deobfuscate_str(&client_id[0], TWITCH_HASH);
if (!GetToken(TWITCH_TOKEN_URL, client_id, TWITCH_SCOPE_VERSION)) if (!GetToken(TWITCH_TOKEN_URL, client_id, TWITCH_SCOPE_VERSION)) {
return false; return false;
if (token.empty()) }
if (token.empty()) {
return false; return false;
if (!key_.empty()) }
if (!key_.empty()) {
return true; return true;
}
Json json; Json json;
bool success = MakeApiRequest("users", json); bool success = MakeApiRequest("users", json);
if (!success) if (!success) {
return false; return false;
}
name = json["data"][0]["login"].string_value(); name = json["data"][0]["login"].string_value();
std::string path = "streams/key?broadcaster_id=" + json["data"][0]["id"].string_value(); std::string path = "streams/key?broadcaster_id=" + json["data"][0]["id"].string_value();
success = MakeApiRequest(path.c_str(), json); success = MakeApiRequest(path.c_str(), json);
if (!success) if (!success) {
return false; return false;
}
key_ = json["data"][0]["stream_key"].string_value(); key_ = json["data"][0]["stream_key"].string_value();
@@ -167,8 +177,9 @@ static inline std::string get_config_str(OBSBasic *main, const char *section, co
bool TwitchAuth::LoadInternal() bool TwitchAuth::LoadInternal()
{ {
if (!cef) if (!cef) {
return false; return false;
}
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
name = get_config_str(main, service(), "Name"); name = get_config_str(main, service(), "Name");
@@ -197,12 +208,15 @@ static const char *referrer_script2 = "'; }});";
void TwitchAuth::LoadUI() void TwitchAuth::LoadUI()
{ {
if (!cef) if (!cef) {
return; return;
if (uiLoaded) }
if (uiLoaded) {
return; return;
if (!GetChannelInfo()) }
if (!GetChannelInfo()) {
return; return;
}
OBSBasic::InitBrowserPanelSafeBlock(); OBSBasic::InitBrowserPanelSafeBlock();
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
@@ -253,11 +267,13 @@ void TwitchAuth::LoadUI()
const int twAddonChoice = config_get_int(main->Config(), service(), "AddonChoice"); const int twAddonChoice = config_get_int(main->Config(), service(), "AddonChoice");
if (twAddonChoice) { if (twAddonChoice) {
if (twAddonChoice & 0x1) if (twAddonChoice & 0x1) {
script += bttv_script; script += bttv_script;
if (twAddonChoice & 0x2) }
if (twAddonChoice & 0x2) {
script += ffz_script; script += ffz_script;
} }
}
browser->setStartupScript(script); browser->setStartupScript(script);
@@ -305,11 +321,13 @@ void TwitchAuth::LoadSecondaryUIPanes()
const int twAddonChoice = config_get_int(main->Config(), service(), "AddonChoice"); const int twAddonChoice = config_get_int(main->Config(), service(), "AddonChoice");
if (twAddonChoice) { if (twAddonChoice) {
if (twAddonChoice & 0x1) if (twAddonChoice & 0x1) {
script += bttv_script; script += bttv_script;
if (twAddonChoice & 0x2) }
if (twAddonChoice & 0x2) {
script += ffz_script; script += ffz_script;
} }
}
/* ----------------------------------- */ /* ----------------------------------- */
@@ -396,10 +414,11 @@ void TwitchAuth::LoadSecondaryUIPanes()
const char *dockStateStr = config_get_string(main->Config(), service(), "DockState"); const char *dockStateStr = config_get_string(main->Config(), service(), "DockState");
QByteArray dockState = QByteArray::fromBase64(QByteArray(dockStateStr)); QByteArray dockState = QByteArray::fromBase64(QByteArray(dockStateStr));
if (main->isVisible() || !main->isMaximized()) if (main->isVisible() || !main->isMaximized()) {
main->restoreState(dockState); main->restoreState(dockState);
} }
} }
}
/* Twitch.tv has an OAuth for itself. If we try to load multiple panel pages /* Twitch.tv has an OAuth for itself. If we try to load multiple panel pages
* at once before it's OAuth'ed itself, they will all try to perform the auth * at once before it's OAuth'ed itself, they will all try to perform the auth
@@ -474,15 +493,17 @@ static std::shared_ptr<Auth> CreateTwitchAuth()
static void DeleteCookies() static void DeleteCookies()
{ {
if (panel_cookies) if (panel_cookies) {
panel_cookies->DeleteCookies("twitch.tv", std::string()); panel_cookies->DeleteCookies("twitch.tv", std::string());
} }
}
void RegisterTwitchAuth() void RegisterTwitchAuth()
{ {
#if !defined(__APPLE__) && !defined(_WIN32) #if !defined(__APPLE__) && !defined(_WIN32)
if (QApplication::platformName().contains("wayland")) if (QApplication::platformName().contains("wayland")) {
return; return;
}
#endif #endif
OAuth::RegisterOAuth(twitchDef, CreateTwitchAuth, TwitchAuth::Login, DeleteCookies); OAuth::RegisterOAuth(twitchDef, CreateTwitchAuth, TwitchAuth::Login, DeleteCookies);
+12 -6
View File
@@ -58,8 +58,9 @@ YoutubeAuth::YoutubeAuth(const Def &d) : OAuthStreamKey(d), section(SECTION_NAME
YoutubeAuth::~YoutubeAuth() YoutubeAuth::~YoutubeAuth()
{ {
if (!uiLoaded) if (!uiLoaded) {
return; return;
}
#ifdef BROWSER_AVAILABLE #ifdef BROWSER_AVAILABLE
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
@@ -107,12 +108,14 @@ bool YoutubeAuth::LoadInternal()
void YoutubeAuth::LoadUI() void YoutubeAuth::LoadUI()
{ {
if (uiLoaded) if (uiLoaded) {
return; return;
}
#ifdef BROWSER_AVAILABLE #ifdef BROWSER_AVAILABLE
if (!cef) if (!cef) {
return; return;
}
OBSBasic::InitBrowserPanelSafeBlock(); OBSBasic::InitBrowserPanelSafeBlock();
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
@@ -191,8 +194,9 @@ QString YoutubeAuth::GenerateState()
QRandomGenerator *rng = QRandomGenerator::system(); QRandomGenerator *rng = QRandomGenerator::system();
int i; int i;
for (i = 0; i < YOUTUBE_API_STATE_LENGTH; i++) for (i = 0; i < YOUTUBE_API_STATE_LENGTH; i++) {
state[i] = allowedChars[rng->bounded(0, allowedCount)]; state[i] = allowedChars[rng->bounded(0, allowedCount)];
}
state[i] = 0; state[i] = 0;
return state; return state;
@@ -285,8 +289,9 @@ std::shared_ptr<Auth> YoutubeAuth::Login(QWidget *owner, const std::string &serv
dlg.exec(); dlg.exec();
#endif #endif
if (dlg.result() == QMessageBox::Cancel || dlg.result() == QDialog::Rejected) if (dlg.result() == QMessageBox::Cancel || dlg.result() == QDialog::Rejected) {
return nullptr; return nullptr;
}
if (!auth->GetToken(YOUTUBE_TOKEN_URL, clientid, secret, QT_TO_UTF8(redirect_uri), YOUTUBE_SCOPE_VERSION, if (!auth->GetToken(YOUTUBE_TOKEN_URL, clientid, secret, QT_TO_UTF8(redirect_uri), YOUTUBE_SCOPE_VERSION,
QT_TO_UTF8(auth_code), true)) { QT_TO_UTF8(auth_code), true)) {
@@ -297,8 +302,9 @@ std::shared_ptr<Auth> YoutubeAuth::Login(QWidget *owner, const std::string &serv
config_remove_value(config, "YouTube", "ChannelName"); config_remove_value(config, "YouTube", "ChannelName");
ChannelDescription cd; ChannelDescription cd;
if (auth->GetChannelDescription(cd)) if (auth->GetChannelDescription(cd)) {
config_set_string(config, "YouTube", "ChannelName", QT_TO_UTF8(cd.title)); config_set_string(config, "YouTube", "ChannelName", QT_TO_UTF8(cd.title));
}
config_save_safe(config, "tmp", nullptr); config_save_safe(config, "tmp", nullptr);
return auth; return auth;
+72 -36
View File
@@ -127,8 +127,9 @@ static inline void LogStringChunk(fstream &logFile, char *str, int log_level)
while (*nextLine) { while (*nextLine) {
char *nextLine = strchr(str, '\n'); char *nextLine = strchr(str, '\n');
if (!nextLine) if (!nextLine) {
break; break;
}
if (nextLine != str && nextLine[-1] == '\r') { if (nextLine != str && nextLine[-1] == '\r') {
nextLine[-1] = 0; nextLine[-1] = 0;
@@ -150,8 +151,9 @@ static inline void LogStringChunk(fstream &logFile, char *str, int log_level)
static inline int sum_chars(const char *str) static inline int sum_chars(const char *str)
{ {
int val = 0; int val = 0;
for (; *str != 0; str++) for (; *str != 0; str++) {
val += *str; val += *str;
}
return val; return val;
} }
@@ -228,13 +230,15 @@ static void do_log(int log_level, const char *msg, va_list args, void *param)
#if !defined(_WIN32) && !defined(_DEBUG) #if !defined(_WIN32) && !defined(_DEBUG)
def_log_handler(log_level, msg, args2, nullptr); def_log_handler(log_level, msg, args2, nullptr);
#endif #endif
if (!too_many_repeated_entries(logFile, msg, str)) if (!too_many_repeated_entries(logFile, msg, str)) {
LogStringChunk(logFile, str, log_level); LogStringChunk(logFile, str, log_level);
} }
}
#if defined(_WIN32) && defined(OBS_DEBUGBREAK_ON_ERROR) #if defined(_WIN32) && defined(OBS_DEBUGBREAK_ON_ERROR)
if (log_level <= LOG_ERROR && IsDebuggerPresent()) if (log_level <= LOG_ERROR && IsDebuggerPresent()) {
__debugbreak(); __debugbreak();
}
#endif #endif
#ifndef _WIN32 #ifndef _WIN32
@@ -245,10 +249,12 @@ static void do_log(int log_level, const char *msg, va_list args, void *param)
static bool get_token(lexer *lex, string &str, base_token_type type) static bool get_token(lexer *lex, string &str, base_token_type type)
{ {
base_token token; base_token token;
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE)) if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE)) {
return false; return false;
if (token.type != type) }
if (token.type != type) {
return false; return false;
}
str.assign(token.text.array, token.text.len); str.assign(token.text.array, token.text.len);
return true; return true;
@@ -257,10 +263,12 @@ static bool get_token(lexer *lex, string &str, base_token_type type)
static bool expect_token(lexer *lex, const char *str, base_token_type type) static bool expect_token(lexer *lex, const char *str, base_token_type type)
{ {
base_token token; base_token token;
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE)) if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE)) {
return false; return false;
if (token.type != type) }
if (token.type != type) {
return false; return false;
}
return strref_cmp(&token.text, str) == 0; return strref_cmp(&token.text, str) == 0;
} }
@@ -274,30 +282,41 @@ static uint64_t convert_log_name(bool has_prefix, const char *name)
if (has_prefix) { if (has_prefix) {
string temp; string temp;
if (!get_token(lex, temp, BASETOKEN_ALPHA)) if (!get_token(lex, temp, BASETOKEN_ALPHA)) {
return 0; return 0;
} }
}
if (!get_token(lex, year, BASETOKEN_DIGIT)) if (!get_token(lex, year, BASETOKEN_DIGIT)) {
return 0; return 0;
if (!expect_token(lex, "-", BASETOKEN_OTHER)) }
if (!expect_token(lex, "-", BASETOKEN_OTHER)) {
return 0; return 0;
if (!get_token(lex, month, BASETOKEN_DIGIT)) }
if (!get_token(lex, month, BASETOKEN_DIGIT)) {
return 0; return 0;
if (!expect_token(lex, "-", BASETOKEN_OTHER)) }
if (!expect_token(lex, "-", BASETOKEN_OTHER)) {
return 0; return 0;
if (!get_token(lex, day, BASETOKEN_DIGIT)) }
if (!get_token(lex, day, BASETOKEN_DIGIT)) {
return 0; return 0;
if (!get_token(lex, hour, BASETOKEN_DIGIT)) }
if (!get_token(lex, hour, BASETOKEN_DIGIT)) {
return 0; return 0;
if (!expect_token(lex, "-", BASETOKEN_OTHER)) }
if (!expect_token(lex, "-", BASETOKEN_OTHER)) {
return 0; return 0;
if (!get_token(lex, minute, BASETOKEN_DIGIT)) }
if (!get_token(lex, minute, BASETOKEN_DIGIT)) {
return 0; return 0;
if (!expect_token(lex, "-", BASETOKEN_OTHER)) }
if (!expect_token(lex, "-", BASETOKEN_OTHER)) {
return 0; return 0;
if (!get_token(lex, second, BASETOKEN_DIGIT)) }
if (!get_token(lex, second, BASETOKEN_DIGIT)) {
return 0; return 0;
}
stringstream timestring; stringstream timestring;
timestring << year << month << day << hour << minute << second; timestring << year << month << day << hour << minute << second;
@@ -318,8 +337,9 @@ static void delete_oldest_file(bool has_prefix, const char *location)
unsigned int count = 0; unsigned int count = 0;
while ((entry = os_readdir(dir)) != NULL) { while ((entry = os_readdir(dir)) != NULL) {
if (entry->directory || *entry->d_name == '.') if (entry->directory || *entry->d_name == '.') {
continue; continue;
}
uint64_t ts = convert_log_name(has_prefix, entry->d_name); uint64_t ts = convert_log_name(has_prefix, entry->d_name);
@@ -353,8 +373,9 @@ static void get_last_log(bool has_prefix, const char *subdir_to_use, std::string
if (dir) { if (dir) {
while ((entry = os_readdir(dir)) != NULL) { while ((entry = os_readdir(dir)) != NULL) {
if (entry->directory || *entry->d_name == '.') if (entry->directory || *entry->d_name == '.') {
continue; continue;
}
uint64_t ts = convert_log_name(has_prefix, entry->d_name); uint64_t ts = convert_log_name(has_prefix, entry->d_name);
@@ -419,12 +440,14 @@ ProfilerSnapshot GetSnapshot()
static void SaveProfilerData(const ProfilerSnapshot &snap) static void SaveProfilerData(const ProfilerSnapshot &snap)
{ {
if (currentLogFile.empty()) if (currentLogFile.empty()) {
return; return;
}
auto pos = currentLogFile.rfind('.'); auto pos = currentLogFile.rfind('.');
if (pos == currentLogFile.npos) if (pos == currentLogFile.npos) {
return; return;
}
#define LITERAL_SIZE(x) x, (sizeof(x) - 1) #define LITERAL_SIZE(x) x, (sizeof(x) - 1)
ostringstream dst; ostringstream dst;
@@ -434,9 +457,10 @@ static void SaveProfilerData(const ProfilerSnapshot &snap)
#undef LITERAL_SIZE #undef LITERAL_SIZE
BPtr<char> path = GetAppConfigPathPtr(dst.str().c_str()); BPtr<char> path = GetAppConfigPathPtr(dst.str().c_str());
if (!profiler_snapshot_dump_csv_gz(snap.get(), path)) if (!profiler_snapshot_dump_csv_gz(snap.get(), path)) {
blog(LOG_WARNING, "Could not save profiler data to '%s'", static_cast<const char *>(path)); blog(LOG_WARNING, "Could not save profiler data to '%s'", static_cast<const char *>(path));
} }
}
static auto ProfilerFree = [](void *) { static auto ProfilerFree = [](void *) {
profiler_stop(); profiler_stop();
@@ -453,8 +477,9 @@ static auto ProfilerFree = [](void *) {
QAccessibleInterface *accessibleFactory(const QString &classname, QObject *object) QAccessibleInterface *accessibleFactory(const QString &classname, QObject *object)
{ {
if (classname == QLatin1String("VolumeSlider") && object && object->isWidgetType()) if (classname == QLatin1String("VolumeSlider") && object && object->isWidgetType()) {
return new VolumeAccessibleInterface(static_cast<QWidget *>(object)); return new VolumeAccessibleInterface(static_cast<QWidget *>(object));
}
return nullptr; return nullptr;
} }
@@ -495,8 +520,9 @@ static int run_program(fstream &logFile, int argc, char *argv[])
* crashes loading saved geometry. Just turn off this theme and let users complain OBS * crashes loading saved geometry. Just turn off this theme and let users complain OBS
* looks ugly instead of crashing. */ * looks ugly instead of crashing. */
const char *platform_theme = getenv("QT_QPA_PLATFORMTHEME"); const char *platform_theme = getenv("QT_QPA_PLATFORMTHEME");
if (platform_theme && strcmp(platform_theme, "qt5ct") == 0) if (platform_theme && strcmp(platform_theme, "qt5ct") == 0) {
unsetenv("QT_QPA_PLATFORMTHEME"); unsetenv("QT_QPA_PLATFORMTHEME");
}
#endif #endif
/* NOTE: This disables an optimisation in Qt that attempts to determine if /* NOTE: This disables an optimisation in Qt that attempts to determine if
@@ -547,8 +573,9 @@ static int run_program(fstream &logFile, int argc, char *argv[])
cancel_launch = mb.clickedButton() == cancelButton; cancel_launch = mb.clickedButton() == cancelButton;
} }
if (cancel_launch) if (cancel_launch) {
return 0; return 0;
}
if (!created_log) { if (!created_log) {
create_log_file(logFile); create_log_file(logFile);
@@ -587,8 +614,9 @@ static int run_program(fstream &logFile, int argc, char *argv[])
} }
#endif #endif
if (!created_log) if (!created_log) {
create_log_file(logFile); create_log_file(logFile);
}
program.checkForUncleanShutdown(); program.checkForUncleanShutdown();
@@ -640,9 +668,10 @@ static int run_program(fstream &logFile, int argc, char *argv[])
mb.setDefaultButton(closeButton); mb.setDefaultButton(closeButton);
mb.exec(); mb.exec();
if (mb.clickedButton() == closeButton) if (mb.clickedButton() == closeButton) {
return 0; return 0;
} }
}
#endif #endif
if (argc > 1) { if (argc > 1) {
@@ -654,8 +683,9 @@ static int run_program(fstream &logFile, int argc, char *argv[])
blog(LOG_INFO, "Command Line Arguments: %s", stor.str().c_str()); blog(LOG_INFO, "Command Line Arguments: %s", stor.str().c_str());
} }
if (!program.OBSInit()) if (!program.OBSInit()) {
return 0; return 0;
}
prof.Stop(); prof.Stop();
@@ -833,11 +863,13 @@ static constexpr char vcRunInstallerUrl[] = "https://obsproject.com/visual-studi
static bool vc_runtime_outdated() static bool vc_runtime_outdated()
{ {
win_version_info ver; win_version_info ver;
if (!get_dll_ver(L"msvcp140.dll", &ver)) if (!get_dll_ver(L"msvcp140.dll", &ver)) {
return true; return true;
}
/* Major is always 14 (hence 140.dll), so we only care about minor. */ /* Major is always 14 (hence 140.dll), so we only care about minor. */
if (ver.minor >= 40) if (ver.minor >= 40) {
return false; return false;
}
int choice = MessageBoxA(NULL, vcRunErrorMsg, vcRunErrorTitle, MB_OKCANCEL | MB_ICONERROR | MB_TASKMODAL); int choice = MessageBoxA(NULL, vcRunErrorMsg, vcRunErrorTitle, MB_OKCANCEL | MB_ICONERROR | MB_TASKMODAL);
if (choice == IDOK) { if (choice == IDOK) {
@@ -907,8 +939,9 @@ int main(int argc, char *argv[])
#ifdef _WIN32 #ifdef _WIN32
// Abort as early as possible if MSVC runtime is outdated // Abort as early as possible if MSVC runtime is outdated
if (vc_runtime_outdated()) if (vc_runtime_outdated()) {
return 1; return 1;
}
// Try to keep this as early as possible // Try to keep this as early as possible
install_dll_blocklist_hook(); install_dll_blocklist_hook();
@@ -981,16 +1014,19 @@ int main(int argc, char *argv[])
opt_start_virtualcam = true; opt_start_virtualcam = true;
} else if (arg_is(argv[i], "--collection", nullptr)) { } else if (arg_is(argv[i], "--collection", nullptr)) {
if (++i < argc) if (++i < argc) {
opt_starting_collection = argv[i]; opt_starting_collection = argv[i];
}
} else if (arg_is(argv[i], "--profile", nullptr)) { } else if (arg_is(argv[i], "--profile", nullptr)) {
if (++i < argc) if (++i < argc) {
opt_starting_profile = argv[i]; opt_starting_profile = argv[i];
}
} else if (arg_is(argv[i], "--scene", nullptr)) { } else if (arg_is(argv[i], "--scene", nullptr)) {
if (++i < argc) if (++i < argc) {
opt_starting_scene = argv[i]; opt_starting_scene = argv[i];
}
} else if (arg_is(argv[i], "--minimize-to-tray", nullptr)) { } else if (arg_is(argv[i], "--minimize-to-tray", nullptr)) {
opt_minimize_tray = true; opt_minimize_tray = true;
+2 -1
View File
@@ -39,8 +39,9 @@ void addModuleToPluginManagerImpl(void *param, obs_module_t *newModule)
std::string moduleName = obs_get_module_file_name(newModule); std::string moduleName = obs_get_module_file_name(newModule);
moduleName = moduleName.substr(0, moduleName.rfind(".")); moduleName = moduleName.substr(0, moduleName.rfind("."));
if (!obs_get_module_allow_disable(moduleName.c_str())) if (!obs_get_module_allow_disable(moduleName.c_str())) {
return; return;
}
const char *display_name = obs_get_module_name(newModule); const char *display_name = obs_get_module_name(newModule);
std::string module_name = moduleName; std::string module_name = moduleName;
File diff suppressed because it is too large Load Diff
+18 -9
View File
@@ -181,8 +181,9 @@ void OBSBasicSettings::on_choose1_clicked()
{ {
QColor color = GetColor(selectRed, QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectRed")); QColor color = GetColor(selectRed, QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectRed"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
selectRed = color_to_int(color); selectRed = color_to_int(color);
@@ -200,8 +201,9 @@ void OBSBasicSettings::on_choose2_clicked()
{ {
QColor color = GetColor(selectGreen, QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectGreen")); QColor color = GetColor(selectGreen, QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectGreen"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
selectGreen = color_to_int(color); selectGreen = color_to_int(color);
@@ -219,8 +221,9 @@ void OBSBasicSettings::on_choose3_clicked()
{ {
QColor color = GetColor(selectBlue, QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectBlue")); QColor color = GetColor(selectBlue, QTStr("Basic.Settings.Accessibility.ColorOverrides.SelectBlue"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
selectBlue = color_to_int(color); selectBlue = color_to_int(color);
@@ -238,8 +241,9 @@ void OBSBasicSettings::on_choose4_clicked()
{ {
QColor color = GetColor(mixerGreen, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerGreen")); QColor color = GetColor(mixerGreen, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerGreen"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
mixerGreen = color_to_int(color); mixerGreen = color_to_int(color);
@@ -257,8 +261,9 @@ void OBSBasicSettings::on_choose5_clicked()
{ {
QColor color = GetColor(mixerYellow, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerYellow")); QColor color = GetColor(mixerYellow, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerYellow"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
mixerYellow = color_to_int(color); mixerYellow = color_to_int(color);
@@ -276,8 +281,9 @@ void OBSBasicSettings::on_choose6_clicked()
{ {
QColor color = GetColor(mixerRed, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerRed")); QColor color = GetColor(mixerRed, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerRed"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
mixerRed = color_to_int(color); mixerRed = color_to_int(color);
@@ -296,8 +302,9 @@ void OBSBasicSettings::on_choose7_clicked()
QColor color = QColor color =
GetColor(mixerGreenActive, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerGreenActive")); GetColor(mixerGreenActive, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerGreenActive"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
mixerGreenActive = color_to_int(color); mixerGreenActive = color_to_int(color);
@@ -316,8 +323,9 @@ void OBSBasicSettings::on_choose8_clicked()
QColor color = QColor color =
GetColor(mixerYellowActive, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerYellowActive")); GetColor(mixerYellowActive, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerYellowActive"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
mixerYellowActive = color_to_int(color); mixerYellowActive = color_to_int(color);
@@ -335,8 +343,9 @@ void OBSBasicSettings::on_choose9_clicked()
{ {
QColor color = GetColor(mixerRedActive, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerRedActive")); QColor color = GetColor(mixerRedActive, QTStr("Basic.Settings.Accessibility.ColorOverrides.MixerRedActive"));
if (!color.isValid()) if (!color.isValid()) {
return; return;
}
mixerRedActive = color_to_int(color); mixerRedActive = color_to_int(color);
@@ -17,8 +17,9 @@ void OBSBasicSettings::InitAppearancePage()
} }
int idx = ui->theme->findData(currentBaseTheme); int idx = ui->theme->findData(currentBaseTheme);
if (idx != -1) if (idx != -1) {
ui->theme->setCurrentIndex(idx); ui->theme->setCurrentIndex(idx);
}
ui->themeVariant->setPlaceholderText(QTStr("Basic.Settings.Appearance.General.NoVariant")); ui->themeVariant->setPlaceholderText(QTStr("Basic.Settings.Appearance.General.NoVariant"));
@@ -41,8 +42,9 @@ void OBSBasicSettings::LoadThemeList(bool reload)
/* Nothing to do if current and last base theme were the same */ /* Nothing to do if current and last base theme were the same */
const QString baseThemeId = ui->theme->currentData().toString(); const QString baseThemeId = ui->theme->currentData().toString();
if (reload && baseThemeId == currentBaseTheme) if (reload && baseThemeId == currentBaseTheme) {
return; return;
}
ui->themeVariant->blockSignals(true); ui->themeVariant->blockSignals(true);
ui->themeVariant->clear(); ui->themeVariant->clear();
@@ -57,20 +59,24 @@ void OBSBasicSettings::LoadThemeList(bool reload)
for (const OBSTheme &theme : themes) { for (const OBSTheme &theme : themes) {
/* Skip non-visible themes */ /* Skip non-visible themes */
if (!theme.isVisible || theme.isHighContrast) if (!theme.isVisible || theme.isHighContrast) {
continue; continue;
}
/* Skip non-child themes */ /* Skip non-child themes */
if (theme.isBaseTheme || theme.parent != baseThemeId) if (theme.isBaseTheme || theme.parent != baseThemeId) {
continue; continue;
}
ui->themeVariant->addItem(theme.name, theme.id); ui->themeVariant->addItem(theme.name, theme.id);
if (baseTheme && theme.filename == baseTheme->filename) if (baseTheme && theme.filename == baseTheme->filename) {
defaultVariant = theme.id; defaultVariant = theme.id;
} }
}
int idx = ui->themeVariant->findData(currentTheme->id); int idx = ui->themeVariant->findData(currentTheme->id);
if (idx != -1) if (idx != -1) {
ui->themeVariant->setCurrentIndex(idx); ui->themeVariant->setCurrentIndex(idx);
}
ui->themeVariant->setEnabled(ui->themeVariant->count() > 0); ui->themeVariant->setEnabled(ui->themeVariant->count() > 0);
ui->themeVariant->blockSignals(false); ui->themeVariant->blockSignals(false);
@@ -89,8 +95,9 @@ void OBSBasicSettings::LoadAppearanceSettings(bool reload)
if (reload) { if (reload) {
QString themeId = ui->theme->currentData().toString(); QString themeId = ui->theme->currentData().toString();
if (ui->themeVariant->currentIndex() != -1) if (ui->themeVariant->currentIndex() != -1) {
themeId = ui->themeVariant->currentData().toString(); themeId = ui->themeVariant->currentData().toString();
}
App()->SetTheme(themeId); App()->SetTheme(themeId);
} }
+156 -80
View File
@@ -114,8 +114,9 @@ void OBSBasicSettings::LoadStream1Settings()
protocol = QT_UTF8(obs_service_get_protocol(service_obj)); protocol = QT_UTF8(obs_service_get_protocol(service_obj));
const char *bearer_token = obs_data_get_string(settings, "bearer_token"); const char *bearer_token = obs_data_get_string(settings, "bearer_token");
if (is_rtmp_custom || is_whip) if (is_rtmp_custom || is_whip) {
ui->customServer->setText(server); ui->customServer->setText(server);
}
if (is_rtmp_custom) { if (is_rtmp_custom) {
ui->service->setCurrentIndex(0); ui->service->setCurrentIndex(0);
@@ -131,8 +132,9 @@ void OBSBasicSettings::LoadStream1Settings()
} else { } else {
int idx = ui->service->findText(service); int idx = ui->service->findText(service);
if (idx == -1) { if (idx == -1) {
if (service && *service) if (service && *service) {
ui->service->insertItem(1, service); ui->service->insertItem(1, service);
}
idx = 1; idx = 1;
} }
ui->service->setCurrentIndex(idx); ui->service->setCurrentIndex(idx);
@@ -156,26 +158,29 @@ void OBSBasicSettings::LoadStream1Settings()
ui->multitrackVideoMaximumVideoTracksAuto->setChecked( ui->multitrackVideoMaximumVideoTracksAuto->setChecked(
config_get_bool(main->Config(), "Stream1", "MultitrackVideoMaximumVideoTracksAuto")); config_get_bool(main->Config(), "Stream1", "MultitrackVideoMaximumVideoTracksAuto"));
if (config_has_user_value(main->Config(), "Stream1", "MultitrackVideoMaximumVideoTracks")) if (config_has_user_value(main->Config(), "Stream1", "MultitrackVideoMaximumVideoTracks")) {
ui->multitrackVideoMaximumVideoTracks->setValue( ui->multitrackVideoMaximumVideoTracks->setValue(
config_get_int(main->Config(), "Stream1", "MultitrackVideoMaximumVideoTracks")); config_get_int(main->Config(), "Stream1", "MultitrackVideoMaximumVideoTracks"));
}
ui->multitrackVideoStreamDumpEnable->setChecked( ui->multitrackVideoStreamDumpEnable->setChecked(
config_get_bool(main->Config(), "Stream1", "MultitrackVideoStreamDumpEnabled")); config_get_bool(main->Config(), "Stream1", "MultitrackVideoStreamDumpEnabled"));
ui->multitrackVideoConfigOverrideEnable->setChecked( ui->multitrackVideoConfigOverrideEnable->setChecked(
config_get_bool(main->Config(), "Stream1", "MultitrackVideoConfigOverrideEnabled")); config_get_bool(main->Config(), "Stream1", "MultitrackVideoConfigOverrideEnabled"));
if (config_has_user_value(main->Config(), "Stream1", "MultitrackVideoConfigOverride")) if (config_has_user_value(main->Config(), "Stream1", "MultitrackVideoConfigOverride")) {
ui->multitrackVideoConfigOverride->setPlainText( ui->multitrackVideoConfigOverride->setPlainText(
DeserializeConfigText( DeserializeConfigText(
config_get_string(main->Config(), "Stream1", "MultitrackVideoConfigOverride")) config_get_string(main->Config(), "Stream1", "MultitrackVideoConfigOverride"))
.c_str()); .c_str());
}
ui->multitrackVideoAdditionalCanvas->clear(); ui->multitrackVideoAdditionalCanvas->clear();
ui->multitrackVideoAdditionalCanvas->addItem(QTStr("None")); ui->multitrackVideoAdditionalCanvas->addItem(QTStr("None"));
for (const auto &canvas : main->GetCanvases()) { for (const auto &canvas : main->GetCanvases()) {
if (obs_canvas_get_flags(canvas) & EPHEMERAL) if (obs_canvas_get_flags(canvas) & EPHEMERAL) {
continue; continue;
}
ui->multitrackVideoAdditionalCanvas->addItem(obs_canvas_get_name(canvas), obs_canvas_get_uuid(canvas)); ui->multitrackVideoAdditionalCanvas->addItem(obs_canvas_get_name(canvas), obs_canvas_get_uuid(canvas));
} }
@@ -200,15 +205,17 @@ void OBSBasicSettings::LoadStream1Settings()
} }
if (idx == -1) { if (idx == -1) {
if (server && *server) if (server && *server) {
ui->server->insertItem(0, server, server); ui->server->insertItem(0, server, server);
}
idx = 0; idx = 0;
} }
ui->server->setCurrentIndex(idx); ui->server->setCurrentIndex(idx);
} }
if (use_custom_server) if (use_custom_server) {
ui->serviceCustomServer->setText(server); ui->serviceCustomServer->setText(server);
}
if (is_whip) { if (is_whip) {
ui->key->setText(bearer_token); ui->key->setText(bearer_token);
@@ -300,8 +307,9 @@ void OBSBasicSettings::SaveStream1Settings()
config_set_int(main->Config(), "Twitch", "AddonChoice", newChoice); config_set_int(main->Config(), "Twitch", "AddonChoice", newChoice);
if (choiceExists && currentChoice != newChoice) if (choiceExists && currentChoice != newChoice) {
forceAuthReload = true; forceAuthReload = true;
}
obs_data_set_bool(settings, "bwtest", ui->bandwidthTestEnable->isChecked()); obs_data_set_bool(settings, "bwtest", ui->bandwidthTestEnable->isChecked());
} else { } else {
@@ -317,8 +325,9 @@ void OBSBasicSettings::SaveStream1Settings()
OBSServiceAutoRelease newService = obs_service_create(service_id, "default_service", settings, hotkeyData); OBSServiceAutoRelease newService = obs_service_create(service_id, "default_service", settings, hotkeyData);
if (!newService) if (!newService) {
return; return;
}
main->SetService(newService); main->SetService(newService);
main->SaveService(); main->SaveService();
@@ -364,8 +373,9 @@ void OBSBasicSettings::SaveStream1Settings()
SaveComboData(ui->multitrackVideoAdditionalCanvas, "Stream1", "MultitrackExtraCanvas"); SaveComboData(ui->multitrackVideoAdditionalCanvas, "Stream1", "MultitrackExtraCanvas");
if (oldMultitrackVideoSetting != ui->enableMultitrackVideo->isChecked() || if (oldMultitrackVideoSetting != ui->enableMultitrackVideo->isChecked() ||
oldWHIPSimulcastTotalLayers != ui->whipSimulcastTotalLayers->value()) oldWHIPSimulcastTotalLayers != ui->whipSimulcastTotalLayers->value()) {
main->ResetOutputs(); main->ResetOutputs();
}
SwapMultiTrack(QT_TO_UTF8(protocol)); SwapMultiTrack(QT_TO_UTF8(protocol));
} }
@@ -473,11 +483,13 @@ void OBSBasicSettings::LoadServices(bool showAll)
names.push_back(name); names.push_back(name);
} }
if (showAll) if (showAll) {
names.sort(Qt::CaseInsensitive); names.sort(Qt::CaseInsensitive);
}
for (QString &name : names) for (QString &name : names) {
ui->service->addItem(name); ui->service->addItem(name);
}
if (obs_is_output_protocol_registered("WHIP")) { if (obs_is_output_protocol_registered("WHIP")) {
ui->service->addItem(QTStr("WHIP"), QVariant((int)ListOpt::WHIP)); ui->service->addItem(QTStr("WHIP"), QVariant((int)ListOpt::WHIP));
@@ -492,9 +504,10 @@ void OBSBasicSettings::LoadServices(bool showAll)
if (!lastService.isEmpty()) { if (!lastService.isEmpty()) {
int idx = ui->service->findText(lastService); int idx = ui->service->findText(lastService);
if (idx != -1) if (idx != -1) {
ui->service->setCurrentIndex(idx); ui->service->setCurrentIndex(idx);
} }
}
ui->service->blockSignals(false); ui->service->blockSignals(false);
} }
@@ -584,9 +597,10 @@ void OBSBasicSettings::on_service_currentIndexChanged(int idx)
if (ServiceSupportsCodecCheck() && UpdateResFPSLimits()) { if (ServiceSupportsCodecCheck() && UpdateResFPSLimits()) {
lastServiceIdx = idx; lastServiceIdx = idx;
if (idx == 0) if (idx == 0) {
lastCustomServer = ui->customServer->text(); lastCustomServer = ui->customServer->text();
} }
}
if (!IsCustomService()) { if (!IsCustomService()) {
ui->advStreamTrackWidget->setCurrentWidget(ui->streamSingleTracks); ui->advStreamTrackWidget->setCurrentWidget(ui->streamSingleTracks);
@@ -609,8 +623,9 @@ void OBSBasicSettings::on_customServer_textChanged(const QString &)
UpdateAdvNetworkGroup(); UpdateAdvNetworkGroup();
UpdateMultitrackVideo(); UpdateMultitrackVideo();
if (ServiceSupportsCodecCheck()) if (ServiceSupportsCodecCheck()) {
lastCustomServer = ui->customServer->text(); lastCustomServer = ui->customServer->text();
}
SwapMultiTrack(QT_TO_UTF8(protocol)); SwapMultiTrack(QT_TO_UTF8(protocol));
} }
@@ -672,19 +687,23 @@ void OBSBasicSettings::ServiceChanged(bool resetFields)
QString OBSBasicSettings::FindProtocol() QString OBSBasicSettings::FindProtocol()
{ {
if (IsCustomService()) { if (IsCustomService()) {
if (ui->customServer->text().isEmpty()) if (ui->customServer->text().isEmpty()) {
return QString("RTMP"); return QString("RTMP");
}
QString server = ui->customServer->text(); QString server = ui->customServer->text();
if (obs_is_output_protocol_registered("RTMPS") && server.startsWith("rtmps://")) if (obs_is_output_protocol_registered("RTMPS") && server.startsWith("rtmps://")) {
return QString("RTMPS"); return QString("RTMPS");
}
if (server.startsWith("srt://")) if (server.startsWith("srt://")) {
return QString("SRT"); return QString("SRT");
}
if (server.startsWith("rist://")) if (server.startsWith("rist://")) {
return QString("RIST"); return QString("RIST");
}
} else { } else {
OBSProperties props = obs_get_service_properties("rtmp_common"); OBSProperties props = obs_get_service_properties("rtmp_common");
@@ -696,9 +715,10 @@ QString OBSBasicSettings::FindProtocol()
obs_property_modified(services, settings); obs_property_modified(services, settings);
const char *protocol = obs_data_get_string(settings, "protocol"); const char *protocol = obs_data_get_string(settings, "protocol");
if (protocol && *protocol) if (protocol && *protocol) {
return QT_UTF8(protocol); return QT_UTF8(protocol);
} }
}
return QString("RTMP"); return QString("RTMP");
} }
@@ -776,10 +796,11 @@ OBSService OBSBasicSettings::SpawnTempService()
obs_data_set_string(settings, "server", QT_TO_UTF8(ui->customServer->text().trimmed())); obs_data_set_string(settings, "server", QT_TO_UTF8(ui->customServer->text().trimmed()));
} }
if (whip) if (whip) {
obs_data_set_string(settings, "bearer_token", QT_TO_UTF8(ui->key->text())); obs_data_set_string(settings, "bearer_token", QT_TO_UTF8(ui->key->text()));
else } else {
obs_data_set_string(settings, "key", QT_TO_UTF8(ui->key->text())); obs_data_set_string(settings, "key", QT_TO_UTF8(ui->key->text()));
}
OBSServiceAutoRelease newService = obs_service_create(service_id, "temp_service", settings, nullptr); OBSServiceAutoRelease newService = obs_service_create(service_id, "temp_service", settings, nullptr);
return newService.Get(); return newService.Get();
@@ -792,8 +813,9 @@ void OBSBasicSettings::OnOAuthStreamKeyConnected()
if (a) { if (a) {
bool validKey = !a->key().empty(); bool validKey = !a->key().empty();
if (validKey) if (validKey) {
ui->key->setText(QT_UTF8(a->key().c_str())); ui->key->setText(QT_UTF8(a->key().c_str()));
}
ui->streamKeyWidget->setVisible(false); ui->streamKeyWidget->setVisible(false);
ui->streamKeyLabel->setVisible(false); ui->streamKeyLabel->setVisible(false);
@@ -918,8 +940,9 @@ void OBSBasicSettings::on_useStreamKey_clicked()
void OBSBasicSettings::on_useAuth_toggled() void OBSBasicSettings::on_useAuth_toggled()
{ {
if (!IsCustomService()) if (!IsCustomService()) {
return; return;
}
bool use_auth = ui->useAuth->isChecked(); bool use_auth = ui->useAuth->isChecked();
@@ -948,11 +971,13 @@ void OBSBasicSettings::UpdateVodTrackSetting()
bool enableVodTrack = ui->service->currentText() == "Twitch"; bool enableVodTrack = ui->service->currentText() == "Twitch";
bool wasEnabled = !!vodTrackCheckbox; bool wasEnabled = !!vodTrackCheckbox;
if (enableForCustomServer && IsCustomService()) if (enableForCustomServer && IsCustomService()) {
enableVodTrack = true; enableVodTrack = true;
}
if (enableVodTrack == wasEnabled) if (enableVodTrack == wasEnabled) {
return; return;
}
if (!enableVodTrack) { if (!enableVodTrack) {
delete vodTrackCheckbox; delete vodTrackCheckbox;
@@ -1041,16 +1066,19 @@ void OBSBasicSettings::UpdateServiceRecommendations()
QString text; QString text;
#define ENFORCE_TEXT(x) QTStr("Basic.Settings.Stream.Recommended." x) #define ENFORCE_TEXT(x) QTStr("Basic.Settings.Stream.Recommended." x)
if (vbitrate) if (vbitrate) {
text += ENFORCE_TEXT("MaxVideoBitrate").arg(QString::number(vbitrate)); text += ENFORCE_TEXT("MaxVideoBitrate").arg(QString::number(vbitrate));
}
if (abitrate) { if (abitrate) {
if (!text.isEmpty()) if (!text.isEmpty()) {
text += "<br>"; text += "<br>";
}
text += ENFORCE_TEXT("MaxAudioBitrate").arg(QString::number(abitrate)); text += ENFORCE_TEXT("MaxAudioBitrate").arg(QString::number(abitrate));
} }
if (res_count) { if (res_count) {
if (!text.isEmpty()) if (!text.isEmpty()) {
text += "<br>"; text += "<br>";
}
obs_service_resolution best_res = {}; obs_service_resolution best_res = {};
int best_res_pixels = 0; int best_res_pixels = 0;
@@ -1068,8 +1096,9 @@ void OBSBasicSettings::UpdateServiceRecommendations()
text += ENFORCE_TEXT("MaxResolution").arg(res_str); text += ENFORCE_TEXT("MaxResolution").arg(res_str);
} }
if (fps) { if (fps) {
if (!text.isEmpty()) if (!text.isEmpty()) {
text += "<br>"; text += "<br>";
}
text += ENFORCE_TEXT("MaxFPS").arg(QString::number(fps)); text += ENFORCE_TEXT("MaxFPS").arg(QString::number(fps));
} }
@@ -1077,8 +1106,9 @@ void OBSBasicSettings::UpdateServiceRecommendations()
#ifdef YOUTUBE_ENABLED #ifdef YOUTUBE_ENABLED
if (IsYouTubeService(QT_TO_UTF8(ui->service->currentText()))) { if (IsYouTubeService(QT_TO_UTF8(ui->service->currentText()))) {
if (!text.isEmpty()) if (!text.isEmpty()) {
text += "<br><br>"; text += "<br><br>";
}
text += "<a href=\"https://www.youtube.com/t/terms\">" text += "<a href=\"https://www.youtube.com/t/terms\">"
"YouTube Terms of Service</a><br>" "YouTube Terms of Service</a><br>"
@@ -1093,8 +1123,9 @@ void OBSBasicSettings::UpdateServiceRecommendations()
void OBSBasicSettings::DisplayEnforceWarning(bool checked) void OBSBasicSettings::DisplayEnforceWarning(bool checked)
{ {
if (IsCustomService()) if (IsCustomService()) {
return; return;
}
if (!checked) { if (!checked) {
SimpleRecordingEncoderChanged(); SimpleRecordingEncoderChanged();
@@ -1119,16 +1150,18 @@ void OBSBasicSettings::DisplayEnforceWarning(bool checked)
bool OBSBasicSettings::ResFPSValid(obs_service_resolution *res_list, size_t res_count, int max_fps) bool OBSBasicSettings::ResFPSValid(obs_service_resolution *res_list, size_t res_count, int max_fps)
{ {
if (!res_count && !max_fps) if (!res_count && !max_fps) {
return true; return true;
}
if (res_count) { if (res_count) {
QString res = ui->outputResolution->currentText(); QString res = ui->outputResolution->currentText();
bool found_res = false; bool found_res = false;
int cx, cy; int cx, cy;
if (sscanf(QT_TO_UTF8(res), "%dx%d", &cx, &cy) != 2) if (sscanf(QT_TO_UTF8(res), "%dx%d", &cx, &cy) != 2) {
return false; return false;
}
for (size_t i = 0; i < res_count; i++) { for (size_t i = 0; i < res_count; i++) {
if (res_list[i].cx == cx && res_list[i].cy == cy) { if (res_list[i].cx == cx && res_list[i].cy == cy) {
@@ -1137,21 +1170,24 @@ bool OBSBasicSettings::ResFPSValid(obs_service_resolution *res_list, size_t res_
} }
} }
if (!found_res) if (!found_res) {
return false; return false;
} }
}
if (max_fps) { if (max_fps) {
int fpsType = ui->fpsType->currentIndex(); int fpsType = ui->fpsType->currentIndex();
if (fpsType != 0) if (fpsType != 0) {
return false; return false;
}
std::string fps_str = ui->fpsCommon->currentText().toStdString(); std::string fps_str = ui->fpsCommon->currentText().toStdString();
float fps; float fps;
sscanf(fps_str.c_str(), "%f", &fps); sscanf(fps_str.c_str(), "%f", &fps);
if (fps > (float)max_fps) if (fps > (float)max_fps) {
return false; return false;
} }
}
return true; return true;
} }
@@ -1177,12 +1213,14 @@ extern void set_closest_res(int &cx, int &cy, struct obs_service_resolution *res
*/ */
bool OBSBasicSettings::UpdateResFPSLimits() bool OBSBasicSettings::UpdateResFPSLimits()
{ {
if (loading) if (loading) {
return false; return false;
}
int idx = ui->service->currentIndex(); int idx = ui->service->currentIndex();
if (idx == -1) if (idx == -1) {
return false; return false;
}
bool ignoreRecommended = ui->ignoreRecommended->isChecked(); bool ignoreRecommended = ui->ignoreRecommended->isChecked();
BPtr<obs_service_resolution> res_list; BPtr<obs_service_resolution> res_list;
@@ -1207,8 +1245,9 @@ bool OBSBasicSettings::UpdateResFPSLimits()
sscanf(QT_TO_UTF8(res), "%dx%d", &cx, &cy); sscanf(QT_TO_UTF8(res), "%dx%d", &cx, &cy);
if (res_count) if (res_count) {
set_closest_res(cx, cy, res_list, res_count); set_closest_res(cx, cy, res_list, res_count);
}
if (max_fps) { if (max_fps) {
int fpsType = ui->fpsType->currentIndex(); int fpsType = ui->fpsType->currentIndex();
@@ -1263,11 +1302,13 @@ bool OBSBasicSettings::UpdateResFPSLimits()
#define WARNING_VAL(x) QTStr("Basic.Settings.Output.Warn.EnforceResolutionFPS." x) #define WARNING_VAL(x) QTStr("Basic.Settings.Output.Warn.EnforceResolutionFPS." x)
QString str; QString str;
if (res_count) if (res_count) {
str += WARNING_VAL("Resolution").arg(res_str); str += WARNING_VAL("Resolution").arg(res_str);
}
if (max_fps) { if (max_fps) {
if (!str.isEmpty()) if (!str.isEmpty()) {
str += "\n"; str += "\n";
}
str += WARNING_VAL("FPS").arg(fps_str); str += WARNING_VAL("FPS").arg(fps_str);
} }
@@ -1275,12 +1316,13 @@ bool OBSBasicSettings::UpdateResFPSLimits()
#undef WARNING_VAL #undef WARNING_VAL
if (button == QMessageBox::No) { if (button == QMessageBox::No) {
if (idx != lastServiceIdx) if (idx != lastServiceIdx) {
QMetaObject::invokeMethod(ui->service, "setCurrentIndex", Qt::QueuedConnection, QMetaObject::invokeMethod(ui->service, "setCurrentIndex", Qt::QueuedConnection,
Q_ARG(int, lastServiceIdx)); Q_ARG(int, lastServiceIdx));
else } else {
QMetaObject::invokeMethod(ui->ignoreRecommended, "setChecked", Qt::QueuedConnection, QMetaObject::invokeMethod(ui->ignoreRecommended, "setChecked", Qt::QueuedConnection,
Q_ARG(bool, true)); Q_ARG(bool, true));
}
return false; return false;
} }
} }
@@ -1303,9 +1345,10 @@ bool OBSBasicSettings::UpdateResFPSLimits()
QString str = QString("%1x%2").arg(QString::number(val.cx), QString::number(val.cy)); QString str = QString("%1x%2").arg(QString::number(val.cx), QString::number(val.cy));
ui->outputResolution->addItem(str); ui->outputResolution->addItem(str);
if (val.cx == cx && val.cy == cy) if (val.cx == cx && val.cy == cy) {
new_res_index = (int)i; new_res_index = (int)i;
} }
}
ui->outputResolution->setCurrentIndex(new_res_index); ui->outputResolution->setCurrentIndex(new_res_index);
if (!valid) { if (!valid) {
@@ -1347,9 +1390,10 @@ bool OBSBasicSettings::UpdateResFPSLimits()
EnableApplyButton(true); EnableApplyButton(true);
} }
} else { } else {
for (int i = 0; i < ui->fpsCommon->count(); i++) for (int i = 0; i < ui->fpsCommon->count(); i++) {
SetComboItemEnabled(ui->fpsCommon, i, true); SetComboItemEnabled(ui->fpsCommon, i, true);
} }
}
SetComboItemEnabled(ui->fpsType, 1, !max_fps); SetComboItemEnabled(ui->fpsType, 1, !max_fps);
SetComboItemEnabled(ui->fpsType, 2, !max_fps); SetComboItemEnabled(ui->fpsType, 2, !max_fps);
@@ -1363,12 +1407,14 @@ bool OBSBasicSettings::UpdateResFPSLimits()
static bool service_supports_codec(const char **codecs, const char *codec) static bool service_supports_codec(const char **codecs, const char *codec)
{ {
if (!codecs) if (!codecs) {
return true; return true;
}
while (*codecs) { while (*codecs) {
if (strcmp(*codecs, codec) == 0) if (strcmp(*codecs, codec) == 0) {
return true; return true;
}
codecs++; codecs++;
} }
@@ -1380,8 +1426,9 @@ extern const char *get_simple_output_encoder(const char *name);
static inline bool service_supports_encoder(const char **codecs, const char *encoder) static inline bool service_supports_encoder(const char **codecs, const char *encoder)
{ {
if (!EncoderAvailable(encoder)) if (!EncoderAvailable(encoder)) {
return false; return false;
}
const char *codec = obs_get_encoder_codec(encoder); const char *codec = obs_get_encoder_codec(encoder);
return service_supports_codec(codecs, codec); return service_supports_codec(codecs, codec);
@@ -1470,14 +1517,18 @@ bool OBSBasicSettings::ServiceAndACodecCompatible()
static QString get_adv_fallback(const QString &enc) static QString get_adv_fallback(const QString &enc)
{ {
if (enc == "obs_nvenc_hevc_tex" || enc == "obs_nvenc_av1_tex" || enc == "jim_hevc_nvenc" || if (enc == "obs_nvenc_hevc_tex" || enc == "obs_nvenc_av1_tex" || enc == "jim_hevc_nvenc" ||
enc == "jim_av1_nvenc") enc == "jim_av1_nvenc") {
return "obs_nvenc_h264_tex"; return "obs_nvenc_h264_tex";
if (enc == "h265_texture_amf" || enc == "av1_texture_amf") }
if (enc == "h265_texture_amf" || enc == "av1_texture_amf") {
return "h264_texture_amf"; return "h264_texture_amf";
if (enc == "com.apple.videotoolbox.videoencoder.ave.hevc") }
if (enc == "com.apple.videotoolbox.videoencoder.ave.hevc") {
return "com.apple.videotoolbox.videoencoder.ave.avc"; return "com.apple.videotoolbox.videoencoder.ave.avc";
if (enc == "obs_qsv11_av1") }
if (enc == "obs_qsv11_av1") {
return "obs_qsv11"; return "obs_qsv11";
}
return "obs_x264"; return "obs_x264";
} }
@@ -1485,42 +1536,50 @@ static QString get_adv_audio_fallback(const QString &enc)
{ {
const char *codec = obs_get_encoder_codec(QT_TO_UTF8(enc)); const char *codec = obs_get_encoder_codec(QT_TO_UTF8(enc));
if (codec && strcmp(codec, "aac") == 0) if (codec && strcmp(codec, "aac") == 0) {
return "ffmpeg_opus"; return "ffmpeg_opus";
}
QString aac_default = "ffmpeg_aac"; QString aac_default = "ffmpeg_aac";
if (EncoderAvailable("CoreAudio_AAC")) if (EncoderAvailable("CoreAudio_AAC")) {
aac_default = "CoreAudio_AAC"; aac_default = "CoreAudio_AAC";
else if (EncoderAvailable("libfdk_aac")) } else if (EncoderAvailable("libfdk_aac")) {
aac_default = "libfdk_aac"; aac_default = "libfdk_aac";
}
return aac_default; return aac_default;
} }
static QString get_simple_fallback(const QString &enc) static QString get_simple_fallback(const QString &enc)
{ {
if (enc == SIMPLE_ENCODER_NVENC_HEVC || enc == SIMPLE_ENCODER_NVENC_AV1) if (enc == SIMPLE_ENCODER_NVENC_HEVC || enc == SIMPLE_ENCODER_NVENC_AV1) {
return SIMPLE_ENCODER_NVENC; return SIMPLE_ENCODER_NVENC;
if (enc == SIMPLE_ENCODER_AMD_HEVC || enc == SIMPLE_ENCODER_AMD_AV1) }
if (enc == SIMPLE_ENCODER_AMD_HEVC || enc == SIMPLE_ENCODER_AMD_AV1) {
return SIMPLE_ENCODER_AMD; return SIMPLE_ENCODER_AMD;
if (enc == SIMPLE_ENCODER_APPLE_HEVC) }
if (enc == SIMPLE_ENCODER_APPLE_HEVC) {
return SIMPLE_ENCODER_APPLE_H264; return SIMPLE_ENCODER_APPLE_H264;
if (enc == SIMPLE_ENCODER_QSV_AV1) }
if (enc == SIMPLE_ENCODER_QSV_AV1) {
return SIMPLE_ENCODER_QSV; return SIMPLE_ENCODER_QSV;
}
return SIMPLE_ENCODER_X264; return SIMPLE_ENCODER_X264;
} }
bool OBSBasicSettings::ServiceSupportsCodecCheck() bool OBSBasicSettings::ServiceSupportsCodecCheck()
{ {
if (loading) if (loading) {
return false; return false;
}
bool vcodec_compat = ServiceAndVCodecCompatible(); bool vcodec_compat = ServiceAndVCodecCompatible();
bool acodec_compat = ServiceAndACodecCompatible(); bool acodec_compat = ServiceAndACodecCompatible();
if (vcodec_compat && acodec_compat) { if (vcodec_compat && acodec_compat) {
if (lastServiceIdx != ui->service->currentIndex() || IsCustomService()) if (lastServiceIdx != ui->service->currentIndex() || IsCustomService()) {
ResetEncoders(true); ResetEncoders(true);
}
return true; return true;
} }
@@ -1568,19 +1627,21 @@ bool OBSBasicSettings::ServiceSupportsCodecCheck()
QString msg = WARNING_VAL("Msg").arg(service, vcodec_compat ? cur_audio_name : cur_video_name, QString msg = WARNING_VAL("Msg").arg(service, vcodec_compat ? cur_audio_name : cur_video_name,
vcodec_compat ? fb_audio_name : fb_video_name); vcodec_compat ? fb_audio_name : fb_video_name);
if (!vcodec_compat && !acodec_compat) if (!vcodec_compat && !acodec_compat) {
msg = WARNING_VAL("Msg2").arg(service, cur_video_name, cur_audio_name, fb_video_name, fb_audio_name); msg = WARNING_VAL("Msg2").arg(service, cur_video_name, cur_audio_name, fb_video_name, fb_audio_name);
}
auto button = OBSMessageBox::question(this, WARNING_VAL("Title"), msg); auto button = OBSMessageBox::question(this, WARNING_VAL("Title"), msg);
#undef WARNING_VAL #undef WARNING_VAL
if (button == QMessageBox::No) { if (button == QMessageBox::No) {
if (lastServiceIdx == 0 && lastServiceIdx == ui->service->currentIndex()) if (lastServiceIdx == 0 && lastServiceIdx == ui->service->currentIndex()) {
QMetaObject::invokeMethod(ui->customServer, "setText", Qt::QueuedConnection, QMetaObject::invokeMethod(ui->customServer, "setText", Qt::QueuedConnection,
Q_ARG(QString, lastCustomServer)); Q_ARG(QString, lastCustomServer));
else } else {
QMetaObject::invokeMethod(ui->service, "setCurrentIndex", Qt::QueuedConnection, QMetaObject::invokeMethod(ui->service, "setCurrentIndex", Qt::QueuedConnection,
Q_ARG(int, lastServiceIdx)); Q_ARG(int, lastServiceIdx));
}
return false; return false;
} }
@@ -1650,22 +1711,27 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
QString qType = QT_UTF8(type); QString qType = QT_UTF8(type);
if (obs_get_encoder_type(type) == OBS_ENCODER_VIDEO) { if (obs_get_encoder_type(type) == OBS_ENCODER_VIDEO) {
if ((caps & ENCODER_HIDE_FLAGS) != 0) if ((caps & ENCODER_HIDE_FLAGS) != 0) {
continue; continue;
}
if (service_supports_codec(vcodecs, codec)) if (service_supports_codec(vcodecs, codec)) {
ui->advOutEncoder->addItem(qName, qType); ui->advOutEncoder->addItem(qName, qType);
if (!streamOnly) }
if (!streamOnly) {
ui->advOutRecEncoder->addItem(qName, qType); ui->advOutRecEncoder->addItem(qName, qType);
} }
}
if (obs_get_encoder_type(type) == OBS_ENCODER_AUDIO) { if (obs_get_encoder_type(type) == OBS_ENCODER_AUDIO) {
if (service_supports_codec(acodecs, codec)) if (service_supports_codec(acodecs, codec)) {
ui->advOutAEncoder->addItem(qName, qType); ui->advOutAEncoder->addItem(qName, qType);
if (!streamOnly) }
if (!streamOnly) {
ui->advOutRecAEncoder->addItem(qName, qType); ui->advOutRecAEncoder->addItem(qName, qType);
} }
} }
}
ui->advOutEncoder->model()->sort(0); ui->advOutEncoder->model()->sort(0);
ui->advOutAEncoder->model()->sort(0); ui->advOutAEncoder->model()->sort(0);
@@ -1684,26 +1750,34 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software"), QString(SIMPLE_ENCODER_X264)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software"), QString(SIMPLE_ENCODER_X264));
#ifdef _WIN32 #ifdef _WIN32
if (service_supports_encoder(vcodecs, "obs_qsv11")) if (service_supports_encoder(vcodecs, "obs_qsv11")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.QSV.H264"), QString(SIMPLE_ENCODER_QSV)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.QSV.H264"), QString(SIMPLE_ENCODER_QSV));
if (service_supports_encoder(vcodecs, "obs_qsv11_av1")) }
if (service_supports_encoder(vcodecs, "obs_qsv11_av1")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.QSV.AV1"), QString(SIMPLE_ENCODER_QSV_AV1)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.QSV.AV1"), QString(SIMPLE_ENCODER_QSV_AV1));
}
#endif #endif
if (service_supports_encoder(vcodecs, "ffmpeg_nvenc")) if (service_supports_encoder(vcodecs, "ffmpeg_nvenc")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.NVENC.H264"), QString(SIMPLE_ENCODER_NVENC)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.NVENC.H264"), QString(SIMPLE_ENCODER_NVENC));
if (service_supports_encoder(vcodecs, "obs_nvenc_av1_tex")) }
if (service_supports_encoder(vcodecs, "obs_nvenc_av1_tex")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.NVENC.AV1"), QString(SIMPLE_ENCODER_NVENC_AV1)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.NVENC.AV1"), QString(SIMPLE_ENCODER_NVENC_AV1));
}
#ifdef ENABLE_HEVC #ifdef ENABLE_HEVC
if (service_supports_encoder(vcodecs, "h265_texture_amf")) if (service_supports_encoder(vcodecs, "h265_texture_amf")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.AMD.HEVC"), QString(SIMPLE_ENCODER_AMD_HEVC)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.AMD.HEVC"), QString(SIMPLE_ENCODER_AMD_HEVC));
if (service_supports_encoder(vcodecs, "ffmpeg_hevc_nvenc")) }
if (service_supports_encoder(vcodecs, "ffmpeg_hevc_nvenc")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.NVENC.HEVC"), ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.NVENC.HEVC"),
QString(SIMPLE_ENCODER_NVENC_HEVC)); QString(SIMPLE_ENCODER_NVENC_HEVC));
}
#endif #endif
if (service_supports_encoder(vcodecs, "h264_texture_amf")) if (service_supports_encoder(vcodecs, "h264_texture_amf")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.AMD.H264"), QString(SIMPLE_ENCODER_AMD)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.AMD.H264"), QString(SIMPLE_ENCODER_AMD));
if (service_supports_encoder(vcodecs, "av1_texture_amf")) }
if (service_supports_encoder(vcodecs, "av1_texture_amf")) {
ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.AMD.AV1"), QString(SIMPLE_ENCODER_AMD_AV1)); ui->simpleOutStrEncoder->addItem(ENCODER_STR("Hardware.AMD.AV1"), QString(SIMPLE_ENCODER_AMD_AV1));
}
/* Preprocessor guard required for the macOS version check */ /* Preprocessor guard required for the macOS version check */
#ifdef __APPLE__ #ifdef __APPLE__
if (service_supports_encoder(vcodecs, "com.apple.videotoolbox.videoencoder.ave.avc") if (service_supports_encoder(vcodecs, "com.apple.videotoolbox.videoencoder.ave.avc")
@@ -1730,10 +1804,12 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly)
#endif #endif
#endif #endif
if (service_supports_encoder(acodecs, "CoreAudio_AAC") || service_supports_encoder(acodecs, "libfdk_aac") || if (service_supports_encoder(acodecs, "CoreAudio_AAC") || service_supports_encoder(acodecs, "libfdk_aac") ||
service_supports_encoder(acodecs, "ffmpeg_aac")) service_supports_encoder(acodecs, "ffmpeg_aac")) {
ui->simpleOutStrAEncoder->addItem(QTStr("Basic.Settings.Output.Simple.Codec.AAC.Default"), "aac"); ui->simpleOutStrAEncoder->addItem(QTStr("Basic.Settings.Output.Simple.Codec.AAC.Default"), "aac");
if (service_supports_encoder(acodecs, "ffmpeg_opus")) }
if (service_supports_encoder(acodecs, "ffmpeg_opus")) {
ui->simpleOutStrAEncoder->addItem(QTStr("Basic.Settings.Output.Simple.Codec.Opus"), "opus"); ui->simpleOutStrAEncoder->addItem(QTStr("Basic.Settings.Output.Simple.Codec.Opus"), "opus");
}
#undef ENCODER_STR #undef ENCODER_STR
/* ------------------------------------------------- */ /* ------------------------------------------------- */
+12 -6
View File
@@ -29,8 +29,9 @@
void OBSHotkeyEdit::keyPressEvent(QKeyEvent *event) void OBSHotkeyEdit::keyPressEvent(QKeyEvent *event)
{ {
if (event->isAutoRepeat()) if (event->isAutoRepeat()) {
return; return;
}
obs_key_combination_t new_key; obs_key_combination_t new_key;
@@ -70,11 +71,13 @@ QVariant OBSHotkeyEdit::inputMethodQuery(Qt::InputMethodQuery query) const
#ifdef __APPLE__ #ifdef __APPLE__
void OBSHotkeyEdit::keyReleaseEvent(QKeyEvent *event) void OBSHotkeyEdit::keyReleaseEvent(QKeyEvent *event)
{ {
if (event->isAutoRepeat()) if (event->isAutoRepeat()) {
return; return;
}
if (event->key() != Qt::Key_CapsLock) if (event->key() != Qt::Key_CapsLock) {
return; return;
}
obs_key_combination_t new_key; obs_key_combination_t new_key;
@@ -140,8 +143,9 @@ void OBSHotkeyEdit::mousePressEvent(QMouseEvent *event)
void OBSHotkeyEdit::HandleNewKey(obs_key_combination_t new_key) void OBSHotkeyEdit::HandleNewKey(obs_key_combination_t new_key)
{ {
if (new_key == key || obs_key_combination_is_empty(new_key)) if (new_key == key || obs_key_combination_is_empty(new_key)) {
return; return;
}
key = new_key; key = new_key;
@@ -181,11 +185,13 @@ void OBSHotkeyEdit::ClearKey()
void OBSHotkeyEdit::UpdateDuplicationState() void OBSHotkeyEdit::UpdateDuplicationState()
{ {
if (!dupeIcon && !hasDuplicate) if (!dupeIcon && !hasDuplicate) {
return; return;
}
if (!dupeIcon) if (!dupeIcon) {
CreateDupeIcon(); CreateDupeIcon();
}
if (dupeIcon->isVisible() != hasDuplicate) { if (dupeIcon->isVisible() != hasDuplicate) {
dupeIcon->setVisible(hasDuplicate); dupeIcon->setVisible(hasDuplicate);
+8 -4
View File
@@ -33,8 +33,9 @@ static inline void updateStyle(QWidget *widget)
void OBSHotkeyLabel::highlightPair(bool highlight) void OBSHotkeyLabel::highlightPair(bool highlight)
{ {
if (!pairPartner) if (!pairPartner) {
return; return;
}
pairPartner->setProperty("class", highlight ? "text-bright" : ""); pairPartner->setProperty("class", highlight ? "text-bright" : "");
updateStyle(pairPartner); updateStyle(pairPartner);
@@ -45,8 +46,9 @@ void OBSHotkeyLabel::highlightPair(bool highlight)
void OBSHotkeyLabel::enterEvent(QEnterEvent *event) void OBSHotkeyLabel::enterEvent(QEnterEvent *event)
{ {
if (!pairPartner) if (!pairPartner) {
return; return;
}
event->accept(); event->accept();
highlightPair(true); highlightPair(true);
@@ -54,8 +56,9 @@ void OBSHotkeyLabel::enterEvent(QEnterEvent *event)
void OBSHotkeyLabel::leaveEvent(QEvent *event) void OBSHotkeyLabel::leaveEvent(QEvent *event)
{ {
if (!pairPartner) if (!pairPartner) {
return; return;
}
event->accept(); event->accept();
highlightPair(false); highlightPair(false);
@@ -64,6 +67,7 @@ void OBSHotkeyLabel::leaveEvent(QEvent *event)
void OBSHotkeyLabel::setToolTip(const QString &toolTip) void OBSHotkeyLabel::setToolTip(const QString &toolTip)
{ {
QLabel::setToolTip(toolTip); QLabel::setToolTip(toolTip);
if (widget) if (widget) {
widget->setToolTip(toolTip); widget->setToolTip(toolTip);
} }
}
+24 -12
View File
@@ -26,12 +26,14 @@
void OBSHotkeyWidget::SetKeyCombinations(const std::vector<obs_key_combination_t> &combos) void OBSHotkeyWidget::SetKeyCombinations(const std::vector<obs_key_combination_t> &combos)
{ {
if (combos.empty()) if (combos.empty()) {
AddEdit({0, OBS_KEY_NONE}); AddEdit({0, OBS_KEY_NONE});
}
for (auto combo : combos) for (auto combo : combos) {
AddEdit(combo); AddEdit(combo);
} }
}
bool OBSHotkeyWidget::Changed() const bool OBSHotkeyWidget::Changed() const
{ {
@@ -47,17 +49,20 @@ void OBSHotkeyWidget::Apply()
changed = false; changed = false;
for (auto &revertButton : revertButtons) for (auto &revertButton : revertButtons) {
revertButton->setEnabled(false); revertButton->setEnabled(false);
} }
}
void OBSHotkeyWidget::GetCombinations(std::vector<obs_key_combination_t> &combinations) const void OBSHotkeyWidget::GetCombinations(std::vector<obs_key_combination_t> &combinations) const
{ {
combinations.clear(); combinations.clear();
for (auto &edit : edits) for (auto &edit : edits) {
if (!obs_key_combination_is_empty(edit->key)) if (!obs_key_combination_is_empty(edit->key)) {
combinations.emplace_back(edit->key); combinations.emplace_back(edit->key);
} }
}
}
void OBSHotkeyWidget::Save() void OBSHotkeyWidget::Save()
{ {
@@ -130,8 +135,9 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
subLayout->addWidget(add); subLayout->addWidget(add);
subLayout->addWidget(remove); subLayout->addWidget(remove);
if (removeButtons.size() == 1) if (removeButtons.size() == 1) {
removeButtons.front()->setEnabled(true); removeButtons.front()->setEnabled(true);
}
if (idx != -1) { if (idx != -1) {
revertButtons.insert(begin(revertButtons) + idx, revert); revertButtons.insert(begin(revertButtons) + idx, revert);
@@ -172,8 +178,9 @@ void OBSHotkeyWidget::RemoveEdit(size_t idx, bool signal)
} }
delete item; delete item;
if (removeButtons.size() == 1) if (removeButtons.size() == 1) {
removeButtons.front()->setEnabled(false); removeButtons.front()->setEnabled(false);
}
emit KeyChanged(); emit KeyChanged();
} }
@@ -188,13 +195,15 @@ void OBSHotkeyWidget::BindingsChanged(void *data, calldata_t *param)
void OBSHotkeyWidget::HandleChangedBindings(obs_hotkey_id id_) void OBSHotkeyWidget::HandleChangedBindings(obs_hotkey_id id_)
{ {
if (ignoreChangedBindings || id != id_) if (ignoreChangedBindings || id != id_) {
return; return;
}
std::vector<obs_key_combination_t> bindings; std::vector<obs_key_combination_t> bindings;
auto LoadBindings = [&](obs_hotkey_binding_t *binding) { auto LoadBindings = [&](obs_hotkey_binding_t *binding) {
if (obs_hotkey_binding_get_hotkey_id(binding) != id) if (obs_hotkey_binding_get_hotkey_id(binding) != id) {
return; return;
}
auto get_combo = obs_hotkey_binding_get_key_combination; auto get_combo = obs_hotkey_binding_get_key_combination;
bindings.push_back(get_combo(binding)); bindings.push_back(get_combo(binding));
@@ -209,16 +218,18 @@ void OBSHotkeyWidget::HandleChangedBindings(obs_hotkey_id id_)
}, },
static_cast<void *>(&LoadBindings)); static_cast<void *>(&LoadBindings));
while (edits.size() > 0) while (edits.size() > 0) {
RemoveEdit(edits.size() - 1, false); RemoveEdit(edits.size() - 1, false);
}
SetKeyCombinations(bindings); SetKeyCombinations(bindings);
} }
void OBSHotkeyWidget::enterEvent(QEnterEvent *event) void OBSHotkeyWidget::enterEvent(QEnterEvent *event)
{ {
if (!label) if (!label) {
return; return;
}
event->accept(); event->accept();
label->highlightPair(true); label->highlightPair(true);
@@ -226,8 +237,9 @@ void OBSHotkeyWidget::enterEvent(QEnterEvent *event)
void OBSHotkeyWidget::leaveEvent(QEvent *event) void OBSHotkeyWidget::leaveEvent(QEvent *event)
{ {
if (!label) if (!label) {
return; return;
}
event->accept(); event->accept();
label->highlightPair(false); label->highlightPair(false);
+2 -1
View File
@@ -63,9 +63,10 @@ public:
void setToolTip(const QString &toolTip_) void setToolTip(const QString &toolTip_)
{ {
toolTip = toolTip_; toolTip = toolTip_;
for (auto &edit : edits) for (auto &edit : edits) {
edit->setToolTip(toolTip_); edit->setToolTip(toolTip_);
} }
}
void Apply(); void Apply();
void GetCombinations(std::vector<obs_key_combination_t> &) const; void GetCombinations(std::vector<obs_key_combination_t> &) const;
+16 -10
View File
@@ -47,29 +47,35 @@ bool CalculateFileHash(const wchar_t *path, B2Hash &hash)
{ {
static __declspec(thread) vector<BYTE> hashBuffer; static __declspec(thread) vector<BYTE> hashBuffer;
blake2b_state blake2; blake2b_state blake2;
if (blake2b_init(&blake2, kBlake2HashLength) != 0) if (blake2b_init(&blake2, kBlake2HashLength) != 0) {
return false; return false;
}
hashBuffer.resize(1048576); hashBuffer.resize(1048576);
WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE) {
return false; return false;
}
for (;;) { for (;;) {
DWORD read = 0; DWORD read = 0;
if (!ReadFile(handle, hashBuffer.data(), (DWORD)hashBuffer.size(), &read, nullptr)) if (!ReadFile(handle, hashBuffer.data(), (DWORD)hashBuffer.size(), &read, nullptr)) {
return false;
if (!read)
break;
if (blake2b_update(&blake2, hashBuffer.data(), read) != 0)
return false; return false;
} }
if (blake2b_final(&blake2, hash.data(), hash.size()) != 0) if (!read) {
break;
}
if (blake2b_update(&blake2, hashBuffer.data(), read) != 0) {
return false; return false;
}
}
if (blake2b_final(&blake2, hash.data(), hash.size()) != 0) {
return false;
}
return true; return true;
} }
+4 -2
View File
@@ -14,9 +14,10 @@ public:
inline CustomHandle(T in) : handle(in) {} inline CustomHandle(T in) : handle(in) {}
inline ~CustomHandle() inline ~CustomHandle()
{ {
if (handle) if (handle) {
freefunc(handle); freefunc(handle);
} }
}
inline T *operator&() { return &handle; } inline T *operator&() { return &handle; }
inline operator T() const { return handle; } inline operator T() const { return handle; }
@@ -24,8 +25,9 @@ public:
inline CustomHandle<T, freefunc> &operator=(T in) inline CustomHandle<T, freefunc> &operator=(T in)
{ {
if (handle) if (handle) {
freefunc(handle); freefunc(handle);
}
handle = in; handle = in;
return *this; return *this;
} }
+20 -10
View File
@@ -67,8 +67,9 @@ bool HTTPPostData(const wchar_t *url, const BYTE *data, int dataLen, const wchar
WinHttpCrackUrl(url, 0, 0, &urlComponents); WinHttpCrackUrl(url, 0, 0, &urlComponents);
if (urlComponents.nPort == 443) if (urlComponents.nPort == 443) {
secure = true; secure = true;
}
/* -------------------------------------- * /* -------------------------------------- *
* connect to server */ * connect to server */
@@ -146,8 +147,9 @@ bool HTTPPostData(const wchar_t *url, const BYTE *data, int dataLen, const wchar
*responseCode = wcstoul(statusCode, nullptr, 10); *responseCode = wcstoul(statusCode, nullptr, 10);
/* are we supposed to return true here? */ /* are we supposed to return true here? */
if (!bResults || *responseCode != 200) if (!bResults || *responseCode != 200) {
return true; return true;
}
BYTE buffer[READ_BUF_SIZE]; BYTE buffer[READ_BUF_SIZE];
DWORD dwSize, outSize; DWORD dwSize, outSize;
@@ -167,8 +169,9 @@ bool HTTPPostData(const wchar_t *url, const BYTE *data, int dataLen, const wchar
return false; return false;
} }
if (!outSize) if (!outSize) {
break; break;
}
if (!ReadHTTPData(responseBuf, buffer, outSize)) { if (!ReadHTTPData(responseBuf, buffer, outSize)) {
*responseCode = -6; *responseCode = -6;
@@ -240,8 +243,9 @@ bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url, const wchar_t *outputPa
WinHttpCrackUrl(url, 0, 0, &urlComponents); WinHttpCrackUrl(url, 0, 0, &urlComponents);
if (urlComponents.nPort == 443) if (urlComponents.nPort == 443) {
secure = true; secure = true;
}
/* -------------------------------------- * /* -------------------------------------- *
* request data */ * request data */
@@ -287,8 +291,9 @@ bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url, const wchar_t *outputPa
*responseCode = wcstoul(statusCode, nullptr, 10); *responseCode = wcstoul(statusCode, nullptr, 10);
/* are we supposed to return true here? */ /* are we supposed to return true here? */
if (!bResults || *responseCode != 200) if (!bResults || *responseCode != 200) {
return true; return true;
}
BYTE buffer[READ_BUF_SIZE]; BYTE buffer[READ_BUF_SIZE];
DWORD dwSize, outSize; DWORD dwSize, outSize;
@@ -313,11 +318,13 @@ bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url, const wchar_t *outputPa
*responseCode = -9; *responseCode = -9;
return false; return false;
} else { } else {
if (!outSize) if (!outSize) {
break; break;
}
if (!ReadHTTPFile(updateFile, buffer, outSize, responseCode)) if (!ReadHTTPFile(updateFile, buffer, outSize, responseCode)) {
return false; return false;
}
UpdateProgressBar(); UpdateProgressBar();
} }
@@ -358,8 +365,9 @@ bool HTTPGetBuffer(HINTERNET hConnect, const wchar_t *url, const wchar_t *extraH
WinHttpCrackUrl(url, 0, 0, &urlComponents); WinHttpCrackUrl(url, 0, 0, &urlComponents);
if (urlComponents.nPort == 443) if (urlComponents.nPort == 443) {
secure = true; secure = true;
}
/* -------------------------------------- * /* -------------------------------------- *
* request data */ * request data */
@@ -405,8 +413,9 @@ bool HTTPGetBuffer(HINTERNET hConnect, const wchar_t *url, const wchar_t *extraH
*responseCode = wcstoul(statusCode, nullptr, 10); *responseCode = wcstoul(statusCode, nullptr, 10);
/* are we supposed to return true here? */ /* are we supposed to return true here? */
if (!bResults || *responseCode != 200) if (!bResults || *responseCode != 200) {
return true; return true;
}
BYTE buffer[READ_BUF_SIZE]; BYTE buffer[READ_BUF_SIZE];
DWORD dwSize, outSize; DWORD dwSize, outSize;
@@ -425,8 +434,9 @@ bool HTTPGetBuffer(HINTERNET hConnect, const wchar_t *url, const wchar_t *extraH
*responseCode = -9; *responseCode = -9;
return false; return false;
} else { } else {
if (!outSize) if (!outSize) {
break; break;
}
out.insert(out.end(), (std::byte *)buffer, (std::byte *)buffer + outSize); out.insert(out.end(), (std::byte *)buffer, (std::byte *)buffer + outSize);
+20 -10
View File
@@ -42,8 +42,9 @@ static int64_t offtin(const uint8_t *buf)
y = y * 256; y = y * 256;
y += buf[0]; y += buf[0];
if (buf[7] & 0x80) if (buf[7] & 0x80) {
y = -y; y = -y;
}
return y; return y;
} }
@@ -65,21 +66,24 @@ try {
* open patch and file to patch */ * open patch and file to patch */
hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr); hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (!hTarget.Valid()) if (!hTarget.Valid()) {
throw int(GetLastError()); throw int(GetLastError());
}
/* --------------------------------- * /* --------------------------------- *
* read patch header */ * read patch header */
if (memcmp(patch_data, kDeltaMagic, kMagicSize) != 0) if (memcmp(patch_data, kDeltaMagic, kMagicSize) != 0) {
throw int(-4); throw int(-4);
}
/* --------------------------------- * /* --------------------------------- *
* allocate new file size data */ * allocate new file size data */
newsize = offtin((const uint8_t *)patch_data + kMagicSize); newsize = offtin((const uint8_t *)patch_data + kMagicSize);
if (newsize < 0 || newsize >= 0x7ffffffff) if (newsize < 0 || newsize >= 0x7ffffffff) {
throw int(-5); throw int(-5);
}
vector<std::byte> newData; vector<std::byte> newData;
try { try {
@@ -95,8 +99,9 @@ try {
DWORD oldFileSize; DWORD oldFileSize;
oldFileSize = GetFileSize(hTarget, nullptr); oldFileSize = GetFileSize(hTarget, nullptr);
if (oldFileSize == INVALID_FILE_SIZE) if (oldFileSize == INVALID_FILE_SIZE) {
throw int(GetLastError()); throw int(GetLastError());
}
vector<std::byte> oldData; vector<std::byte> oldData;
try { try {
@@ -105,10 +110,12 @@ try {
throw int(-1); throw int(-1);
} }
if (!ReadFile(hTarget, oldData.data(), oldFileSize, &read, nullptr)) if (!ReadFile(hTarget, oldData.data(), oldFileSize, &read, nullptr)) {
throw int(GetLastError()); throw int(GetLastError());
if (read != oldFileSize) }
if (read != oldFileSize) {
throw int(-1); throw int(-1);
}
/* --------------------------------- * /* --------------------------------- *
* patch to new file data */ * patch to new file data */
@@ -116,22 +123,25 @@ try {
size_t result = ZSTD_decompress_usingDict(zstdCtx, newData.data(), newData.size(), patch_data + kHeaderSize, size_t result = ZSTD_decompress_usingDict(zstdCtx, newData.data(), newData.size(), patch_data + kHeaderSize,
patch_size - kHeaderSize, oldData.data(), oldData.size()); patch_size - kHeaderSize, oldData.data(), oldData.size());
if (result != newsize || ZSTD_isError(result)) if (result != newsize || ZSTD_isError(result)) {
throw int(-9); throw int(-9);
}
/* --------------------------------- * /* --------------------------------- *
* write new file */ * write new file */
hTarget = nullptr; hTarget = nullptr;
hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr); hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr);
if (!hTarget.Valid()) if (!hTarget.Valid()) {
throw int(GetLastError()); throw int(GetLastError());
}
DWORD written; DWORD written;
success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize, &written, nullptr); success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize, &written, nullptr);
if (!success || written != newsize) if (!success || written != newsize) {
throw int(GetLastError()); throw int(GetLastError());
}
return 0; return 0;
+171 -87
View File
@@ -91,16 +91,19 @@ static bool IsVSRedistOutdated()
const wchar_t vc_dll[] = L"msvcp140"; const wchar_t vc_dll[] = L"msvcp140";
auto size = GetFileVersionInfoSize(vc_dll, nullptr); auto size = GetFileVersionInfoSize(vc_dll, nullptr);
if (!size) if (!size) {
return true; return true;
}
buf.resize(size); buf.resize(size);
if (!GetFileVersionInfo(vc_dll, 0, size, buf.data())) if (!GetFileVersionInfo(vc_dll, 0, size, buf.data())) {
return true; return true;
}
bool success = VerQueryValue(buf.data(), L"\\", reinterpret_cast<LPVOID *>(&info), &len); bool success = VerQueryValue(buf.data(), L"\\", reinterpret_cast<LPVOID *>(&info), &len);
if (!success || !info || !len) if (!success || !info || !len) {
return true; return true;
}
return LOWORD(info->dwFileVersionMS) < 40; return LOWORD(info->dwFileVersionMS) < 40;
} }
@@ -114,8 +117,9 @@ static void Log(const wchar_t *fmt, ...)
int len = _vscwprintf(fmt, argptr); int len = _vscwprintf(fmt, argptr);
va_end(argptr); va_end(argptr);
if (len <= 0) if (len <= 0) {
return; return;
}
/* Using len + 1 for null terminator, which gets chopped off below */ /* Using len + 1 for null terminator, which gets chopped off below */
wstring str(len + 1, L'\0'); wstring str(len + 1, L'\0');
@@ -124,8 +128,9 @@ static void Log(const wchar_t *fmt, ...)
len = _vsnwprintf_s(str.data(), len + 1, _TRUNCATE, fmt, argptr); len = _vsnwprintf_s(str.data(), len + 1, _TRUNCATE, fmt, argptr);
va_end(argptr); va_end(argptr);
if (len <= 0) if (len <= 0) {
return; return;
}
/* Append newline and send to main window as a PostMessage to /* Append newline and send to main window as a PostMessage to
* avoid blocking worker threads with UI messages */ * avoid blocking worker threads with UI messages */
@@ -159,29 +164,35 @@ try {
hSrc = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, hSrc = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
nullptr); nullptr);
if (!hSrc.Valid()) if (!hSrc.Valid()) {
throw LastError(); throw LastError();
}
hDest = CreateFile(dest, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr); hDest = CreateFile(dest, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr);
if (!hDest.Valid()) if (!hDest.Valid()) {
throw LastError(); throw LastError();
}
BYTE buf[65536]; BYTE buf[65536];
DWORD read, wrote; DWORD read, wrote;
for (;;) { for (;;) {
if (!ReadFile(hSrc, buf, sizeof(buf), &read, nullptr)) if (!ReadFile(hSrc, buf, sizeof(buf), &read, nullptr)) {
throw LastError(); throw LastError();
}
if (read == 0) if (read == 0) {
break; break;
}
if (!WriteFile(hDest, buf, read, &wrote, nullptr)) if (!WriteFile(hDest, buf, read, &wrote, nullptr)) {
throw LastError(); throw LastError();
}
if (wrote != read) if (wrote != read) {
return false; return false;
} }
}
return true; return true;
@@ -193,12 +204,14 @@ try {
static void MyDeleteFile(const wstring &filename) static void MyDeleteFile(const wstring &filename)
{ {
/* Try straightforward delete first */ /* Try straightforward delete first */
if (DeleteFile(filename.c_str())) if (DeleteFile(filename.c_str())) {
return; return;
}
DWORD err = GetLastError(); DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND) if (err == ERROR_FILE_NOT_FOUND) {
return; return;
}
/* If all else fails, schedule the file to be deleted on reboot */ /* If all else fails, schedule the file to be deleted on reboot */
MoveFileEx(filename.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); MoveFileEx(filename.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT);
@@ -208,18 +221,22 @@ static bool IsSafeFilename(const wchar_t *path)
{ {
const wchar_t *p = path; const wchar_t *p = path;
if (!*p) if (!*p) {
return false; return false;
}
if (wcsstr(path, L"..")) if (wcsstr(path, L"..")) {
return false; return false;
}
if (*p == '/') if (*p == '/') {
return false; return false;
}
while (*p) { while (*p) {
if (!isalnum(*p) && *p != '.' && *p != '/' && *p != '_' && *p != '-') if (!isalnum(*p) && *p != '.' && *p != '/' && *p != '_' && *p != '-') {
return false; return false;
}
p++; p++;
} }
@@ -258,12 +275,14 @@ static bool QuickWriteFile(const wchar_t *file, const void *data, size_t size)
try { try {
WinHandle handle = CreateFile(file, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr); WinHandle handle = CreateFile(file, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE) {
throw LastError(); throw LastError();
}
DWORD written; DWORD written;
if (!WriteFile(handle, data, (DWORD)size, &written, nullptr)) if (!WriteFile(handle, data, (DWORD)size, &written, nullptr)) {
throw LastError(); throw LastError();
}
return true; return true;
@@ -351,9 +370,10 @@ struct deletion_t {
void UndoRename() const void UndoRename() const
{ {
if (!deleteMeFilename.empty()) if (!deleteMeFilename.empty()) {
MoveFile(deleteMeFilename.c_str(), originalFilename.c_str()); MoveFile(deleteMeFilename.c_str(), originalFilename.c_str());
} }
}
}; };
static unordered_map<B2Hash, vector<std::byte>> download_data; static unordered_map<B2Hash, vector<std::byte>> download_data;
@@ -364,12 +384,14 @@ static mutex updateMutex;
static inline void CleanupPartialUpdates() static inline void CleanupPartialUpdates()
{ {
for (update_t &update : updates) for (update_t &update : updates) {
update.CleanPartialUpdate(); update.CleanPartialUpdate();
}
for (deletion_t &deletion : deletions) for (deletion_t &deletion : deletions) {
deletion.UndoRename(); deletion.UndoRename();
} }
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
@@ -387,10 +409,12 @@ static int Decompress(ZSTD_DCtx *ctx, std::vector<std::byte> &buf, size_t size)
// Overwrite buffer with decompressed data // Overwrite buffer with decompressed data
size_t result = ZSTD_decompressDCtx(ctx, buf.data(), buf.size(), comp.data(), comp.size()); size_t result = ZSTD_decompressDCtx(ctx, buf.data(), buf.size(), comp.data(), comp.size());
if (result != size) if (result != size) {
return -9; return -9;
if (ZSTD_isError(result)) }
if (ZSTD_isError(result)) {
return -10; return -10;
}
return 0; return 0;
} }
@@ -440,8 +464,9 @@ bool DownloadWorkerThread()
return false; return false;
} }
if (update.state != STATE_PENDING_DOWNLOAD) if (update.state != STATE_PENDING_DOWNLOAD) {
continue; continue;
}
update.state = STATE_DOWNLOADING; update.state = STATE_DOWNLOADING;
@@ -554,22 +579,26 @@ static inline DWORD WaitIfOBS(DWORD id, const wchar_t *expected)
*path = 0; *path = 0;
WinHandle proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | SYNCHRONIZE, false, id); WinHandle proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | SYNCHRONIZE, false, id);
if (!proc.Valid()) if (!proc.Valid()) {
return WAITIFOBS_WRONG_PROCESS; return WAITIFOBS_WRONG_PROCESS;
}
if (!QueryFullProcessImageNameW(proc, 0, path, &path_len)) if (!QueryFullProcessImageNameW(proc, 0, path, &path_len)) {
return WAITIFOBS_WRONG_PROCESS; return WAITIFOBS_WRONG_PROCESS;
}
// check it's actually our exe that's running // check it's actually our exe that's running
size_t len = wcslen(obs_base_directory); size_t len = wcslen(obs_base_directory);
if (wcsncmp(path, obs_base_directory, len) != 0) if (wcsncmp(path, obs_base_directory, len) != 0) {
return WAITIFOBS_WRONG_PROCESS; return WAITIFOBS_WRONG_PROCESS;
}
name = wcsrchr(path, L'\\'); name = wcsrchr(path, L'\\');
if (name) if (name) {
name += 1; name += 1;
else } else {
name = path; name = path;
}
if (_wcsnicmp(name, expected, 5) == 0) { if (_wcsnicmp(name, expected, 5) == 0) {
HANDLE hWait[2]; HANDLE hWait[2];
@@ -579,8 +608,9 @@ static inline DWORD WaitIfOBS(DWORD id, const wchar_t *expected)
Log(L"Waiting for OBS PID %d at %s...", id, path); Log(L"Waiting for OBS PID %d at %s...", id, path);
int i = WaitForMultipleObjects(2, hWait, false, INFINITE); int i = WaitForMultipleObjects(2, hWait, false, INFINITE);
if (i == WAIT_OBJECT_0 + 1) if (i == WAIT_OBJECT_0 + 1) {
return WAITIFOBS_CANCELLED; return WAITIFOBS_CANCELLED;
}
return WAITIFOBS_SUCCESS; return WAITIFOBS_SUCCESS;
} }
@@ -640,8 +670,9 @@ void HasherThread()
while (true) { while (true) {
ulock.lock(); ulock.lock();
if (hashQueue.empty()) if (hashQueue.empty()) {
return; return;
}
auto fileName = hashQueue.front(); auto fileName = hashQueue.front();
hashQueue.pop(); hashQueue.pop();
@@ -650,11 +681,13 @@ void HasherThread()
wchar_t updateFileName[MAX_PATH]; wchar_t updateFileName[MAX_PATH];
if (!UTF8ToWideBuf(updateFileName, fileName.c_str())) if (!UTF8ToWideBuf(updateFileName, fileName.c_str())) {
continue; continue;
}
if (!IsSafeFilename(updateFileName)) if (!IsSafeFilename(updateFileName)) {
continue; continue;
}
B2Hash existingHash; B2Hash existingHash;
if (CalculateFileHash(updateFileName, existingHash)) { if (CalculateFileHash(updateFileName, existingHash)) {
@@ -698,16 +731,18 @@ static inline bool FileExists(const wchar_t *path)
HANDLE hFind; HANDLE hFind;
hFind = FindFirstFileW(path, &wfd); hFind = FindFirstFileW(path, &wfd);
if (hFind != INVALID_HANDLE_VALUE) if (hFind != INVALID_HANDLE_VALUE) {
FindClose(hFind); FindClose(hFind);
}
return hFind != INVALID_HANDLE_VALUE; return hFind != INVALID_HANDLE_VALUE;
} }
static bool NonCorePackageInstalled(const char *name) static bool NonCorePackageInstalled(const char *name)
{ {
if (strcmp(name, "obs-browser") == 0) if (strcmp(name, "obs-browser") == 0) {
return FileExists(L"obs-plugins\\64bit\\obs-browser.dll"); return FileExists(L"obs-plugins\\64bit\\obs-browser.dll");
}
return false; return false;
} }
@@ -715,29 +750,34 @@ static bool NonCorePackageInstalled(const char *name)
static bool AddPackageUpdateFiles(const Package &package, const wchar_t *branch) static bool AddPackageUpdateFiles(const Package &package, const wchar_t *branch)
{ {
wchar_t wPackageName[512]; wchar_t wPackageName[512];
if (!UTF8ToWideBuf(wPackageName, package.name.c_str())) if (!UTF8ToWideBuf(wPackageName, package.name.c_str())) {
return false; return false;
}
if (package.name != "core" && !NonCorePackageInstalled(package.name.c_str())) if (package.name != "core" && !NonCorePackageInstalled(package.name.c_str())) {
return true; return true;
}
for (const File &file : package.files) { for (const File &file : package.files) {
if (file.hash.size() != kBlake2StrLength) if (file.hash.size() != kBlake2StrLength) {
continue; continue;
}
/* The download hash may not exist if a file is uncompressed */ /* The download hash may not exist if a file is uncompressed */
bool compressed = false; bool compressed = false;
if (file.compressed_hash.size() == kBlake2StrLength) if (file.compressed_hash.size() == kBlake2StrLength) {
compressed = true; compressed = true;
}
/* convert strings to wide */ /* convert strings to wide */
wchar_t sourceURL[1024]; wchar_t sourceURL[1024];
wchar_t updateFileName[MAX_PATH]; wchar_t updateFileName[MAX_PATH];
if (!UTF8ToWideBuf(updateFileName, file.name.c_str())) if (!UTF8ToWideBuf(updateFileName, file.name.c_str())) {
continue; continue;
}
/* make sure paths are safe */ /* make sure paths are safe */
@@ -762,8 +802,9 @@ static bool AddPackageUpdateFiles(const Package &package, const wchar_t *branch)
if (hashes.count(file.name)) { if (hashes.count(file.name)) {
localFileHash = hashes[file.name]; localFileHash = hashes[file.name];
if (localFileHash == updateHash) if (localFileHash == updateHash) {
continue; continue;
}
has_hash = true; has_hash = true;
} }
@@ -787,8 +828,9 @@ static bool AddPackageUpdateFiles(const Package &package, const wchar_t *branch)
} }
update.has_hash = has_hash; update.has_hash = has_hash;
if (has_hash) if (has_hash) {
update.my_hash = localFileHash; update.my_hash = localFileHash;
}
updates.push_back(std::move(update)); updates.push_back(std::move(update));
@@ -802,19 +844,22 @@ static void AddPackageRemovedFiles(const Package &package)
{ {
for (const string &filename : package.removed_files) { for (const string &filename : package.removed_files) {
wchar_t removedFileName[MAX_PATH]; wchar_t removedFileName[MAX_PATH];
if (!UTF8ToWideBuf(removedFileName, filename.c_str())) if (!UTF8ToWideBuf(removedFileName, filename.c_str())) {
continue; continue;
}
/* Ensure paths are safe, also check if file exists */ /* Ensure paths are safe, also check if file exists */
if (!IsSafeFilename(removedFileName)) if (!IsSafeFilename(removedFileName)) {
continue; continue;
}
/* Technically GetFileAttributes can fail for other reasons, /* Technically GetFileAttributes can fail for other reasons,
* so double-check by also checking the last error */ * so double-check by also checking the last error */
if (GetFileAttributesW(removedFileName) == INVALID_FILE_ATTRIBUTES) { if (GetFileAttributesW(removedFileName) == INVALID_FILE_ATTRIBUTES) {
int err = GetLastError(); int err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
continue; continue;
} }
}
deletion_t deletion; deletion_t deletion;
deletion.originalFilename = removedFileName; deletion.originalFilename = removedFileName;
@@ -836,8 +881,9 @@ static bool RenameRemovedFile(deletion_t &deletion)
blake2b(hash.data(), hash.size(), junk, sizeof(junk), nullptr, 0); blake2b(hash.data(), hash.size(), junk, sizeof(junk), nullptr, 0);
HashToString(hash, temp); HashToString(hash, temp);
if (!UTF8ToWideBuf(randomStr, temp.c_str())) if (!UTF8ToWideBuf(randomStr, temp.c_str())) {
return false; return false;
}
randomStr[8] = 0; randomStr[8] = 0;
@@ -861,25 +907,31 @@ static bool UpdateWithPatchIfAvailable(const PatchResponse &patch)
wchar_t widePatchableFilename[MAX_PATH]; wchar_t widePatchableFilename[MAX_PATH];
wchar_t sourceURL[1024]; wchar_t sourceURL[1024];
if (patch.source.compare(0, kCDNUrl.size(), kCDNUrl) != 0) if (patch.source.compare(0, kCDNUrl.size(), kCDNUrl) != 0) {
return false; return false;
}
if (patch.name.find('/') == string::npos) if (patch.name.find('/') == string::npos) {
return false; return false;
}
string patchPackageName(patch.name, 0, patch.name.find('/')); string patchPackageName(patch.name, 0, patch.name.find('/'));
string fileName(patch.name, patch.name.find('/') + 1); string fileName(patch.name, patch.name.find('/') + 1);
if (!UTF8ToWideBuf(widePatchableFilename, fileName.c_str())) if (!UTF8ToWideBuf(widePatchableFilename, fileName.c_str())) {
return false; return false;
if (!UTF8ToWideBuf(sourceURL, patch.source.c_str())) }
if (!UTF8ToWideBuf(sourceURL, patch.source.c_str())) {
return false; return false;
}
for (update_t &update : updates) { for (update_t &update : updates) {
if (update.packageName != patchPackageName) if (update.packageName != patchPackageName) {
continue; continue;
if (update.outputPath != widePatchableFilename) }
if (update.outputPath != widePatchableFilename) {
continue; continue;
}
update.patchable = true; update.patchable = true;
@@ -911,8 +963,9 @@ static bool MoveInUseFileAway(const update_t &file)
blake2b(hash.data(), hash.size(), junk, sizeof(junk), nullptr, 0); blake2b(hash.data(), hash.size(), junk, sizeof(junk), nullptr, 0);
HashToString(hash, temp); HashToString(hash, temp);
if (!UTF8ToWideBuf(randomStr, temp.c_str())) if (!UTF8ToWideBuf(randomStr, temp.c_str())) {
return false; return false;
}
randomStr[8] = 0; randomStr[8] = 0;
@@ -956,8 +1009,9 @@ static bool UpdateFile(ZSTD_DCtx *ctx, update_t &file)
if (curFileName) { if (curFileName) {
curFileName[0] = '\0'; curFileName[0] = '\0';
curFileName++; curFileName++;
} else } else {
curFileName = baseName; curFileName = baseName;
}
/* Backup the existing file in case a rollback is needed */ /* Backup the existing file in case a rollback is needed */
StringCbCopy(oldFileRenamedPath, sizeof(oldFileRenamedPath), file.outputPath.c_str()); StringCbCopy(oldFileRenamedPath, sizeof(oldFileRenamedPath), file.outputPath.c_str());
@@ -967,14 +1021,15 @@ static bool UpdateFile(ZSTD_DCtx *ctx, update_t &file)
DWORD err = GetLastError(); DWORD err = GetLastError();
int is_sharing_violation = (err == ERROR_SHARING_VIOLATION || err == ERROR_USER_MAPPED_FILE); int is_sharing_violation = (err == ERROR_SHARING_VIOLATION || err == ERROR_USER_MAPPED_FILE);
if (is_sharing_violation) if (is_sharing_violation) {
Status(L"Update failed: %s is still in use. " Status(L"Update failed: %s is still in use. "
L"Close all programs and try again.", L"Close all programs and try again.",
curFileName); curFileName);
else } else {
Status(L"Update failed: Couldn't backup %s " Status(L"Update failed: Couldn't backup %s "
L"(error %d)", L"(error %d)",
curFileName, GetLastError()); curFileName, GetLastError());
}
return false; return false;
} }
@@ -1028,9 +1083,10 @@ static bool UpdateFile(ZSTD_DCtx *ctx, update_t &file)
if (!already_tried_to_move) { if (!already_tried_to_move) {
already_tried_to_move = true; already_tried_to_move = true;
if (MoveInUseFileAway(file)) if (MoveInUseFileAway(file)) {
goto retryAfterMovingFile; goto retryAfterMovingFile;
} }
}
Status(L"Update failed: %s is still in use. " Status(L"Update failed: %s is still in use. "
L"Close all " L"Close all "
@@ -1092,10 +1148,12 @@ static bool UpdateWorker()
while (true) { while (true) {
ulock.lock(); ulock.lock();
if (updateThreadFailed) if (updateThreadFailed) {
return false; return false;
if (updateQueue.empty()) }
if (updateQueue.empty()) {
break; break;
}
auto update = updateQueue.front(); auto update = updateQueue.front();
updateQueue.pop(); updateQueue.pop();
@@ -1120,8 +1178,9 @@ static bool UpdateWorker()
static bool RunUpdateWorkers(int num) static bool RunUpdateWorkers(int num)
try { try {
for (update_t &update : updates) for (update_t &update : updates) {
updateQueue.emplace(update); updateQueue.emplace(update);
}
vector<future<bool>> thread_success_results; vector<future<bool>> thread_success_results;
thread_success_results.resize(num); thread_success_results.resize(num);
@@ -1274,12 +1333,14 @@ static void UpdateRegistryVersion(const Manifest &manifest)
manifest.version_minor, manifest.version_patch); manifest.version_minor, manifest.version_patch);
} }
if (formattedLen <= 0) if (formattedLen <= 0) {
return; return;
}
res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, regKey, 0, KEY_WRITE | KEY_WOW64_32KEY, &key); res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, regKey, 0, KEY_WRITE | KEY_WOW64_32KEY, &key);
if (res != ERROR_SUCCESS) if (res != ERROR_SUCCESS) {
return; return;
}
RegSetValueExA(key, "DisplayVersion", 0, REG_SZ, (const BYTE *)version, formattedLen + 1); RegSetValueExA(key, "DisplayVersion", 0, REG_SZ, (const BYTE *)version, formattedLen + 1);
RegCloseKey(key); RegCloseKey(key);
@@ -1310,17 +1371,20 @@ static bool Update(wchar_t *cmdLine)
int i = WaitForMultipleObjects(2, hWait, false, INFINITE); int i = WaitForMultipleObjects(2, hWait, false, INFINITE);
if (i == WAIT_OBJECT_0) if (i == WAIT_OBJECT_0) {
ReleaseMutex(hObsUpdateMutex); ReleaseMutex(hObsUpdateMutex);
}
CloseHandle(hObsUpdateMutex); CloseHandle(hObsUpdateMutex);
if (i == WAIT_OBJECT_0 + 1) if (i == WAIT_OBJECT_0 + 1) {
return false; return false;
} }
}
if (!WaitForOBS()) if (!WaitForOBS()) {
return false; return false;
}
/* ------------------------------------- * /* ------------------------------------- *
* Init crypt stuff */ * Init crypt stuff */
@@ -1500,12 +1564,14 @@ static bool Update(wchar_t *cmdLine)
PatchesRequest files; PatchesRequest files;
for (update_t &update : updates) { for (update_t &update : updates) {
if (!update.has_hash) if (!update.has_hash) {
continue; continue;
}
char outputPath[MAX_PATH]; char outputPath[MAX_PATH];
if (!WideToUTF8Buf(outputPath, update.outputPath.c_str())) if (!WideToUTF8Buf(outputPath, update.outputPath.c_str())) {
continue; continue;
}
string hash_string; string hash_string;
HashToString(update.my_hash, hash_string); HashToString(update.my_hash, hash_string);
@@ -1535,22 +1601,25 @@ static bool Update(wchar_t *cmdLine)
size_t result = ZSTD_compress(compressedJson.data(), compressedJson.size(), post_body.data(), size_t result = ZSTD_compress(compressedJson.data(), compressedJson.size(), post_body.data(),
post_body.size(), ZSTD_CLEVEL_DEFAULT); post_body.size(), ZSTD_CLEVEL_DEFAULT);
if (ZSTD_isError(result)) if (ZSTD_isError(result)) {
return false; return false;
}
compressedJson.resize(result); compressedJson.resize(result);
wstring manifestUrl(kPatchManifestURL); wstring manifestUrl(kPatchManifestURL);
if (branch != L"stable") if (branch != L"stable") {
manifestUrl += L"?branch=" + branch; manifestUrl += L"?branch=" + branch;
}
int responseCode; int responseCode;
bool success = !!HTTPPostData(manifestUrl.c_str(), (BYTE *)compressedJson.data(), bool success = !!HTTPPostData(manifestUrl.c_str(), (BYTE *)compressedJson.data(),
(int)compressedJson.size(), L"Accept-Encoding: gzip", &responseCode, (int)compressedJson.size(), L"Accept-Encoding: gzip", &responseCode,
newManifest); newManifest);
if (!success) if (!success) {
return false; return false;
}
if (responseCode != 200) { if (responseCode != 200) {
Status(L"Update failed: HTTP/%d while trying to " Status(L"Update failed: HTTP/%d while trying to "
@@ -1609,13 +1678,15 @@ static bool Update(wchar_t *cmdLine)
* avoiding concurrent map mutation from multiple threads. */ * avoiding concurrent map mutation from multiple threads. */
download_data.reserve(downloadHashes.size()); download_data.reserve(downloadHashes.size());
for (update_t &update : updates) { for (update_t &update : updates) {
if (update.state == STATE_PENDING_DOWNLOAD) if (update.state == STATE_PENDING_DOWNLOAD) {
download_data.try_emplace(update.downloadHash); download_data.try_emplace(update.downloadHash);
} }
}
Status(L"Downloading updates..."); Status(L"Downloading updates...");
if (!RunDownloadWorkers(4)) if (!RunDownloadWorkers(4)) {
return false; return false;
}
if ((size_t)completedUpdates != updates.size()) { if ((size_t)completedUpdates != updates.size()) {
Status(L"Update failed to download all files."); Status(L"Update failed to download all files.");
@@ -1629,8 +1700,9 @@ static bool Update(wchar_t *cmdLine)
lastPosition = 0; lastPosition = 0;
Status(L"Installing updates..."); Status(L"Installing updates...");
if (!RunUpdateWorkers(4)) if (!RunUpdateWorkers(4)) {
return false; return false;
}
for (deletion_t &deletion : deletions) { for (deletion_t &deletion : deletions) {
if (!RenameRemovedFile(deletion)) { if (!RenameRemovedFile(deletion)) {
@@ -1716,13 +1788,15 @@ static bool Update(wchar_t *cmdLine)
/* If we get here, all updates installed successfully so we can purge /* If we get here, all updates installed successfully so we can purge
* the old versions */ * the old versions */
for (update_t &update : updates) { for (update_t &update : updates) {
if (!update.previousFile.empty()) if (!update.previousFile.empty()) {
DeleteFile(update.previousFile.c_str()); DeleteFile(update.previousFile.c_str());
} }
}
/* Delete all removed files mentioned in the manifest */ /* Delete all removed files mentioned in the manifest */
for (deletion_t &deletion : deletions) for (deletion_t &deletion : deletions) {
MyDeleteFile(deletion.deleteMeFilename); MyDeleteFile(deletion.deleteMeFilename);
}
SendDlgItemMessage(hwndMain, IDC_PROGRESS, PBM_SETPOS, 100, 0); SendDlgItemMessage(hwndMain, IDC_PROGRESS, PBM_SETPOS, 100, 0);
@@ -1742,18 +1816,21 @@ static DWORD WINAPI UpdateThread(void *arg)
* partially installed updates */ * partially installed updates */
CleanupPartialUpdates(); CleanupPartialUpdates();
if (tempPath[0]) if (tempPath[0]) {
RemoveDirectory(tempPath); RemoveDirectory(tempPath);
}
if (WaitForSingleObject(cancelRequested, 0) == WAIT_OBJECT_0) if (WaitForSingleObject(cancelRequested, 0) == WAIT_OBJECT_0) {
Status(L"Update aborted."); Status(L"Update aborted.");
}
HWND hProgress = GetDlgItem(hwndMain, IDC_PROGRESS); HWND hProgress = GetDlgItem(hwndMain, IDC_PROGRESS);
/* Even a no-op style change apparently resets the progress bar */ /* Even a no-op style change apparently resets the progress bar */
LONG_PTR style = GetWindowLongPtr(hProgress, GWL_STYLE); LONG_PTR style = GetWindowLongPtr(hProgress, GWL_STYLE);
if (style & PBS_MARQUEE) if (style & PBS_MARQUEE) {
SetWindowLongPtr(hProgress, GWL_STYLE, style & ~PBS_MARQUEE); SetWindowLongPtr(hProgress, GWL_STYLE, style & ~PBS_MARQUEE);
}
SendMessage(hProgress, PBM_SETSTATE, PBST_ERROR, 0); SendMessage(hProgress, PBM_SETSTATE, PBST_ERROR, 0);
@@ -1762,12 +1839,14 @@ static DWORD WINAPI UpdateThread(void *arg)
updateFailed = true; updateFailed = true;
} else { } else {
if (tempPath[0]) if (tempPath[0]) {
RemoveDirectory(tempPath); RemoveDirectory(tempPath);
} }
}
if (bExiting) if (bExiting) {
ExitProcess(success); ExitProcess(success);
}
return 0; return 0;
} }
@@ -1807,8 +1886,9 @@ static void LaunchOBS(LPWSTR lpCmdLine)
execInfo.lpDirectory = newCwd; execInfo.lpDirectory = newCwd;
execInfo.nShow = SW_SHOWNORMAL; execInfo.nShow = SW_SHOWNORMAL;
if (lpCmdLine[0]) if (lpCmdLine[0]) {
execInfo.lpParameters = lpCmdLine; execInfo.lpParameters = lpCmdLine;
}
ShellExecuteEx(&execInfo); ShellExecuteEx(&execInfo);
} }
@@ -1816,8 +1896,9 @@ static void LaunchOBS(LPWSTR lpCmdLine)
static void ToggleLogVisibility() static void ToggleLogVisibility()
{ {
HWND hwndLog = GetDlgItem(hwndMain, IDC_LOG); HWND hwndLog = GetDlgItem(hwndMain, IDC_LOG);
if (!hwndLog) if (!hwndLog) {
return; return;
}
logVisible = !logVisible; logVisible = !logVisible;
@@ -1874,8 +1955,9 @@ static INT_PTR CALLBACK UpdateDialogProc(HWND hwnd, UINT message, WPARAM wParam,
/* Propagate the main window font or it looks ugly */ /* Propagate the main window font or it looks ugly */
HFONT hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); HFONT hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
if (hFont) if (hFont) {
SendMessage(hwndLog, WM_SETFONT, (WPARAM)hFont, FALSE); SendMessage(hwndLog, WM_SETFONT, (WPARAM)hFont, FALSE);
}
return true; return true;
} }
@@ -1885,19 +1967,21 @@ static INT_PTR CALLBACK UpdateDialogProc(HWND hwnd, UINT message, WPARAM wParam,
if (HIWORD(wParam) == BN_CLICKED) { if (HIWORD(wParam) == BN_CLICKED) {
DWORD result = WaitForSingleObject(updateThread, 0); DWORD result = WaitForSingleObject(updateThread, 0);
if (result == WAIT_OBJECT_0) { if (result == WAIT_OBJECT_0) {
if (updateFailed) if (updateFailed) {
PostQuitMessage(0); PostQuitMessage(0);
else } else {
PostQuitMessage(1); PostQuitMessage(1);
}
} else { } else {
EnableWindow((HWND)lParam, false); EnableWindow((HWND)lParam, false);
CancelUpdate(false); CancelUpdate(false);
} }
} }
} else if (LOWORD(wParam) == IDC_LOGBUTTON) { } else if (LOWORD(wParam) == IDC_LOGBUTTON) {
if (HIWORD(wParam) == BN_CLICKED) if (HIWORD(wParam) == BN_CLICKED) {
ToggleLogVisibility(); ToggleLogVisibility();
} }
}
return true; return true;
case WM_CLOSE: case WM_CLOSE:
+106 -59
View File
@@ -38,8 +38,9 @@ static void ApplyEncoderDefaults(OBSData &settings, const obs_encoder_t *encoder
OBSData dataRet = obs_encoder_get_defaults(encoder); OBSData dataRet = obs_encoder_get_defaults(encoder);
obs_data_release(dataRet); obs_data_release(dataRet);
if (!!settings) if (!!settings) {
obs_data_apply(dataRet, settings); obs_data_apply(dataRet, settings);
}
settings = std::move(dataRet); settings = std::move(dataRet);
} }
@@ -79,24 +80,27 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
if (ffmpegOutput) { if (ffmpegOutput) {
fileOutput = obs_output_create("ffmpeg_output", "adv_ffmpeg_output", nullptr, nullptr); fileOutput = obs_output_create("ffmpeg_output", "adv_ffmpeg_output", nullptr, nullptr);
if (!fileOutput) if (!fileOutput) {
throw "Failed to create recording FFmpeg output " throw "Failed to create recording FFmpeg output "
"(advanced output)"; "(advanced output)";
}
} else { } else {
bool useReplayBuffer = config_get_bool(main->Config(), "AdvOut", "RecRB"); bool useReplayBuffer = config_get_bool(main->Config(), "AdvOut", "RecRB");
if (useReplayBuffer) { if (useReplayBuffer) {
OBSDataAutoRelease hotkey; OBSDataAutoRelease hotkey;
const char *str = config_get_string(main->Config(), "Hotkeys", "ReplayBuffer"); const char *str = config_get_string(main->Config(), "Hotkeys", "ReplayBuffer");
if (str) if (str) {
hotkey = obs_data_create_from_json(str); hotkey = obs_data_create_from_json(str);
else } else {
hotkey = nullptr; hotkey = nullptr;
}
replayBuffer = obs_output_create("replay_buffer", Str("ReplayBuffer"), nullptr, hotkey); replayBuffer = obs_output_create("replay_buffer", Str("ReplayBuffer"), nullptr, hotkey);
if (!replayBuffer) if (!replayBuffer) {
throw "Failed to create replay buffer output " throw "Failed to create replay buffer output "
"(simple output)"; "(simple output)";
}
signal_handler_t *signal = obs_output_get_signal_handler(replayBuffer); signal_handler_t *signal = obs_output_get_signal_handler(replayBuffer);
@@ -107,30 +111,34 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
} }
const char *mux = "ffmpeg_muxer"; const char *mux = "ffmpeg_muxer";
if (strcmp(recFormat, "hybrid_mp4") == 0) if (strcmp(recFormat, "hybrid_mp4") == 0) {
mux = "mp4_output"; mux = "mp4_output";
else if (strcmp(recFormat, "hybrid_mov") == 0) } else if (strcmp(recFormat, "hybrid_mov") == 0) {
mux = "mov_output"; mux = "mov_output";
}
fileOutput = obs_output_create(mux, "adv_file_output", nullptr, nullptr); fileOutput = obs_output_create(mux, "adv_file_output", nullptr, nullptr);
if (!fileOutput) if (!fileOutput) {
throw "Failed to create recording output " throw "Failed to create recording output "
"(advanced output)"; "(advanced output)";
}
if (!useStreamEncoder) { if (!useStreamEncoder) {
videoRecording = obs_video_encoder_create(recordEncoder, "advanced_video_recording", videoRecording = obs_video_encoder_create(recordEncoder, "advanced_video_recording",
recordEncSettings, nullptr); recordEncSettings, nullptr);
if (!videoRecording) if (!videoRecording) {
throw "Failed to create recording video " throw "Failed to create recording video "
"encoder (advanced output)"; "encoder (advanced output)";
}
obs_encoder_release(videoRecording); obs_encoder_release(videoRecording);
} }
} }
videoStreaming = obs_video_encoder_create(streamEncoder, "advanced_video_stream", streamEncSettings, nullptr); videoStreaming = obs_video_encoder_create(streamEncoder, "advanced_video_stream", streamEncSettings, nullptr);
if (!videoStreaming) if (!videoStreaming) {
throw "Failed to create streaming video encoder " throw "Failed to create streaming video encoder "
"(advanced output)"; "(advanced output)";
}
obs_encoder_release(videoStreaming); obs_encoder_release(videoStreaming);
if (whipSimulcastEncoders != nullptr) { if (whipSimulcastEncoders != nullptr) {
whipSimulcastEncoders->Create(streamEncoder, config_get_int(main->Config(), "AdvOut", "RescaleFilter"), whipSimulcastEncoders->Create(streamEncoder, config_get_int(main->Config(), "AdvOut", "RescaleFilter"),
@@ -141,8 +149,9 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
const char *rate_control = const char *rate_control =
obs_data_get_string(useStreamEncoder ? streamEncSettings : recordEncSettings, "rate_control"); obs_data_get_string(useStreamEncoder ? streamEncSettings : recordEncSettings, "rate_control");
if (!rate_control) if (!rate_control) {
rate_control = ""; rate_control = "";
}
usesBitrate = astrcmpi(rate_control, "CBR") == 0 || astrcmpi(rate_control, "VBR") == 0 || usesBitrate = astrcmpi(rate_control, "CBR") == 0 || astrcmpi(rate_control, "VBR") == 0 ||
astrcmpi(rate_control, "ABR") == 0; astrcmpi(rate_control, "ABR") == 0;
@@ -175,17 +184,19 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
int streamTrackIndex = config_get_int(main->Config(), "AdvOut", "TrackIndex") - 1; int streamTrackIndex = config_get_int(main->Config(), "AdvOut", "TrackIndex") - 1;
streamAudioEnc = streamAudioEnc =
obs_audio_encoder_create(streamAudioEncoder, "adv_stream_audio", nullptr, streamTrackIndex, nullptr); obs_audio_encoder_create(streamAudioEncoder, "adv_stream_audio", nullptr, streamTrackIndex, nullptr);
if (!streamAudioEnc) if (!streamAudioEnc) {
throw "Failed to create streaming audio encoder " throw "Failed to create streaming audio encoder "
"(advanced output)"; "(advanced output)";
}
obs_encoder_release(streamAudioEnc); obs_encoder_release(streamAudioEnc);
id = ""; id = "";
int vodTrack = config_get_int(main->Config(), "AdvOut", "VodTrackIndex") - 1; int vodTrack = config_get_int(main->Config(), "AdvOut", "VodTrackIndex") - 1;
streamArchiveEnc = obs_audio_encoder_create(streamAudioEncoder, ADV_ARCHIVE_NAME, nullptr, vodTrack, nullptr); streamArchiveEnc = obs_audio_encoder_create(streamAudioEncoder, ADV_ARCHIVE_NAME, nullptr, vodTrack, nullptr);
if (!streamArchiveEnc) if (!streamArchiveEnc) {
throw "Failed to create archive audio encoder " throw "Failed to create archive audio encoder "
"(advanced output)"; "(advanced output)";
}
obs_encoder_release(streamArchiveEnc); obs_encoder_release(streamArchiveEnc);
startRecording.Connect(obs_output_get_signal_handler(fileOutput), "start", OBSStartRecording, this); startRecording.Connect(obs_output_get_signal_handler(fileOutput), "start", OBSStartRecording, this);
@@ -230,14 +241,16 @@ void AdvancedOutput::UpdateStreamSettings()
} }
int enforced_keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); int enforced_keyint_sec = (int)obs_data_get_int(settings, "keyint_sec");
if (keyint_sec != 0 && keyint_sec < enforced_keyint_sec) if (keyint_sec != 0 && keyint_sec < enforced_keyint_sec) {
obs_data_set_int(settings, "keyint_sec", keyint_sec); obs_data_set_int(settings, "keyint_sec", keyint_sec);
}
} else { } else {
blog(LOG_WARNING, "User is ignoring service settings."); blog(LOG_WARNING, "User is ignoring service settings.");
} }
if (dynBitrate && strstr(streamEncoder, "nvenc") != nullptr) if (dynBitrate && strstr(streamEncoder, "nvenc") != nullptr) {
obs_data_set_bool(settings, "lookahead", false); obs_data_set_bool(settings, "lookahead", false);
}
video_t *video = obs_get_video(); video_t *video = obs_get_video();
enum video_format format = video_output_get_format(video); enum video_format format = video_output_get_format(video);
@@ -267,8 +280,9 @@ inline void AdvancedOutput::UpdateRecordingSettings()
void AdvancedOutput::Update() void AdvancedOutput::Update()
{ {
UpdateStreamSettings(); UpdateStreamSettings();
if (!useStreamEncoder && !ffmpegOutput) if (!useStreamEncoder && !ffmpegOutput) {
UpdateRecordingSettings(); UpdateRecordingSettings();
}
UpdateAudioSettings(); UpdateAudioSettings();
} }
@@ -277,8 +291,9 @@ inline bool AdvancedOutput::allowsMultiTrack()
const char *protocol = nullptr; const char *protocol = nullptr;
obs_service_t *service_obj = main->GetService(); obs_service_t *service_obj = main->GetService();
protocol = obs_service_get_protocol(service_obj); protocol = obs_service_get_protocol(service_obj);
if (!protocol) if (!protocol) {
return false; return false;
}
return astrcmpi_n(protocol, SRT_PROTOCOL, strlen(SRT_PROTOCOL)) == 0 || return astrcmpi_n(protocol, SRT_PROTOCOL, strlen(SRT_PROTOCOL)) == 0 ||
astrcmpi_n(protocol, RIST_PROTOCOL, strlen(RIST_PROTOCOL)) == 0; astrcmpi_n(protocol, RIST_PROTOCOL, strlen(RIST_PROTOCOL)) == 0;
} }
@@ -335,10 +350,11 @@ inline void AdvancedOutput::SetupRecording()
bool is_fragmented = strncmp(recFormat, "fragmented", 10) == 0; bool is_fragmented = strncmp(recFormat, "fragmented", 10) == 0;
bool flv = strcmp(recFormat, "flv") == 0; bool flv = strcmp(recFormat, "flv") == 0;
if (flv) if (flv) {
tracks = config_get_int(main->Config(), "AdvOut", "FLVTrack"); tracks = config_get_int(main->Config(), "AdvOut", "FLVTrack");
else } else {
tracks = config_get_int(main->Config(), "AdvOut", "RecTracks"); tracks = config_get_int(main->Config(), "AdvOut", "RecTracks");
}
OBSDataAutoRelease settings = obs_data_create(); OBSDataAutoRelease settings = obs_data_create();
unsigned int cx = 0; unsigned int cx = 0;
@@ -349,13 +365,15 @@ inline void AdvancedOutput::SetupRecording()
* longer possible to select such a configuration in settings, but legacy * longer possible to select such a configuration in settings, but legacy
* configurations might still have this configured and we don't want to * configurations might still have this configured and we don't want to
* just break them. */ * just break them. */
if (tracks == 0) if (tracks == 0) {
tracks = config_get_int(main->Config(), "AdvOut", "TrackIndex"); tracks = config_get_int(main->Config(), "AdvOut", "TrackIndex");
}
if (useStreamEncoder) { if (useStreamEncoder) {
obs_output_set_video_encoder(fileOutput, videoStreaming); obs_output_set_video_encoder(fileOutput, videoStreaming);
if (replayBuffer) if (replayBuffer) {
obs_output_set_video_encoder(replayBuffer, videoStreaming); obs_output_set_video_encoder(replayBuffer, videoStreaming);
}
} else { } else {
if (rescaleFilter != OBS_SCALE_DISABLE && rescaleRes && *rescaleRes) { if (rescaleFilter != OBS_SCALE_DISABLE && rescaleRes && *rescaleRes) {
if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) { if (sscanf(rescaleRes, "%ux%u", &cx, &cy) != 2) {
@@ -367,25 +385,28 @@ inline void AdvancedOutput::SetupRecording()
obs_encoder_set_scaled_size(videoRecording, cx, cy); obs_encoder_set_scaled_size(videoRecording, cx, cy);
obs_encoder_set_gpu_scale_type(videoRecording, (obs_scale_type)rescaleFilter); obs_encoder_set_gpu_scale_type(videoRecording, (obs_scale_type)rescaleFilter);
obs_output_set_video_encoder(fileOutput, videoRecording); obs_output_set_video_encoder(fileOutput, videoRecording);
if (replayBuffer) if (replayBuffer) {
obs_output_set_video_encoder(replayBuffer, videoRecording); obs_output_set_video_encoder(replayBuffer, videoRecording);
} }
}
if (!flv) { if (!flv) {
for (int i = 0; i < MAX_AUDIO_MIXES; i++) { for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
if ((tracks & (1 << i)) != 0) { if ((tracks & (1 << i)) != 0) {
obs_output_set_audio_encoder(fileOutput, recordTrack[i], idx); obs_output_set_audio_encoder(fileOutput, recordTrack[i], idx);
if (replayBuffer) if (replayBuffer) {
obs_output_set_audio_encoder(replayBuffer, recordTrack[i], idx); obs_output_set_audio_encoder(replayBuffer, recordTrack[i], idx);
}
idx++; idx++;
} }
} }
} else if (flv && tracks != 0) { } else if (flv && tracks != 0) {
obs_output_set_audio_encoder(fileOutput, recordTrack[tracks - 1], idx); obs_output_set_audio_encoder(fileOutput, recordTrack[tracks - 1], idx);
if (replayBuffer) if (replayBuffer) {
obs_output_set_audio_encoder(replayBuffer, recordTrack[tracks - 1], idx); obs_output_set_audio_encoder(replayBuffer, recordTrack[tracks - 1], idx);
} }
}
// Use fragmented MOV/MP4 if user has not already specified custom movflags // Use fragmented MOV/MP4 if user has not already specified custom movflags
if (is_fragmented && (!mux || strstr(mux, "movflags") == NULL)) { if (is_fragmented && (!mux || strstr(mux, "movflags") == NULL)) {
@@ -396,17 +417,19 @@ inline void AdvancedOutput::SetupRecording()
} }
obs_data_set_string(settings, "muxer_settings", mux_frag.c_str()); obs_data_set_string(settings, "muxer_settings", mux_frag.c_str());
} else { } else {
if (is_fragmented) if (is_fragmented) {
blog(LOG_WARNING, "User enabled fragmented recording, " blog(LOG_WARNING, "User enabled fragmented recording, "
"but custom muxer settings contained movflags."); "but custom muxer settings contained movflags.");
}
obs_data_set_string(settings, "muxer_settings", mux); obs_data_set_string(settings, "muxer_settings", mux);
} }
obs_data_set_string(settings, "path", path); obs_data_set_string(settings, "path", path);
obs_output_update(fileOutput, settings); obs_output_update(fileOutput, settings);
if (replayBuffer) if (replayBuffer) {
obs_output_update(replayBuffer, settings); obs_output_update(replayBuffer, settings);
} }
}
inline void AdvancedOutput::SetupFFmpeg() inline void AdvancedOutput::SetupFFmpeg()
{ {
@@ -519,15 +542,18 @@ inline void AdvancedOutput::UpdateAudioSettings()
int bitrate = (int)obs_data_get_int(settings[i], "bitrate"); int bitrate = (int)obs_data_get_int(settings[i], "bitrate");
obs_service_apply_encoder_settings(main->GetService(), nullptr, settings[i]); obs_service_apply_encoder_settings(main->GetService(), nullptr, settings[i]);
if (!enforceBitrate) if (!enforceBitrate) {
obs_data_set_int(settings[i], "bitrate", bitrate); obs_data_set_int(settings[i], "bitrate", bitrate);
} }
} }
}
if (track == streamTrackIndex) if (track == streamTrackIndex) {
obs_encoder_update(streamAudioEnc, settings[i]); obs_encoder_update(streamAudioEnc, settings[i]);
if (track == vodTrackIndex) }
if (track == vodTrackIndex) {
obs_encoder_update(streamArchiveEnc, settings[i]); obs_encoder_update(streamArchiveEnc, settings[i]);
}
} else { } else {
obs_encoder_update(streamTrack[i], settings[i]); obs_encoder_update(streamTrack[i], settings[i]);
} }
@@ -537,8 +563,9 @@ inline void AdvancedOutput::UpdateAudioSettings()
void AdvancedOutput::SetupOutputs() void AdvancedOutput::SetupOutputs()
{ {
obs_encoder_set_video(videoStreaming, obs_get_video()); obs_encoder_set_video(videoStreaming, obs_get_video());
if (videoRecording) if (videoRecording) {
obs_encoder_set_video(videoRecording, obs_get_video()); obs_encoder_set_video(videoRecording, obs_get_video());
}
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
obs_encoder_set_audio(streamTrack[i], obs_get_audio()); obs_encoder_set_audio(streamTrack[i], obs_get_audio());
obs_encoder_set_audio(recordTrack[i], obs_get_audio()); obs_encoder_set_audio(recordTrack[i], obs_get_audio());
@@ -548,11 +575,12 @@ void AdvancedOutput::SetupOutputs()
SetupStreaming(); SetupStreaming();
if (ffmpegOutput) if (ffmpegOutput) {
SetupFFmpeg(); SetupFFmpeg();
else } else {
SetupRecording(); SetupRecording();
} }
}
int AdvancedOutput::GetAudioBitrate(size_t i, const char *id) const int AdvancedOutput::GetAudioBitrate(size_t i, const char *id) const
{ {
@@ -576,22 +604,25 @@ inline std::optional<size_t> AdvancedOutput::VodTrackMixerIdx(obs_service_t *ser
} else { } else {
OBSDataAutoRelease settings = obs_service_get_settings(service); OBSDataAutoRelease settings = obs_service_get_settings(service);
const char *service = obs_data_get_string(settings, "service"); const char *service = obs_data_get_string(settings, "service");
if (!ServiceSupportsVodTrack(service)) if (!ServiceSupportsVodTrack(service)) {
vodTrackEnabled = false; vodTrackEnabled = false;
} }
}
if (vodTrackEnabled && streamTrackIndex != vodTrackIndex) if (vodTrackEnabled && streamTrackIndex != vodTrackIndex) {
return {vodTrackIndex - 1}; return {vodTrackIndex - 1};
}
return std::nullopt; return std::nullopt;
} }
inline void AdvancedOutput::SetupVodTrack(obs_service_t *service) inline void AdvancedOutput::SetupVodTrack(obs_service_t *service)
{ {
if (VodTrackMixerIdx(service).has_value()) if (VodTrackMixerIdx(service).has_value()) {
obs_output_set_audio_encoder(streamOutput, streamArchiveEnc, 1); obs_output_set_audio_encoder(streamOutput, streamArchiveEnc, 1);
else } else {
clear_archive_encoder(streamOutput, ADV_ARCHIVE_NAME); clear_archive_encoder(streamOutput, ADV_ARCHIVE_NAME);
} }
}
std::shared_future<void> AdvancedOutput::SetupStreaming(obs_service_t *service, std::shared_future<void> AdvancedOutput::SetupStreaming(obs_service_t *service,
SetupStreamingContinuation_t continuation) SetupStreamingContinuation_t continuation)
@@ -606,12 +637,14 @@ std::shared_future<void> AdvancedOutput::SetupStreaming(obs_service_t *service,
UpdateAudioSettings(); UpdateAudioSettings();
if (!Active()) if (!Active()) {
SetupOutputs(); SetupOutputs();
}
Auth *auth = main->GetAuth(); Auth *auth = main->GetAuth();
if (auth) if (auth) {
auth->OnStreamConfig(); auth->OnStreamConfig();
}
/* --------------------- */ /* --------------------- */
@@ -626,8 +659,9 @@ std::shared_future<void> AdvancedOutput::SetupStreaming(obs_service_t *service,
auto handle_multitrack_video_result = [this, type = std::string{type}, is_multitrack_output, auto handle_multitrack_video_result = [this, type = std::string{type}, is_multitrack_output,
multiTrackAudioMixes](std::optional<bool> multitrackVideoResult) { multiTrackAudioMixes](std::optional<bool> multitrackVideoResult) {
if (multitrackVideoResult.has_value()) if (multitrackVideoResult.has_value()) {
return multitrackVideoResult.value(); return multitrackVideoResult.value();
}
/* XXX: this is messy and disgusting and should be refactored */ /* XXX: this is messy and disgusting and should be refactored */
if (outputType != type) { if (outputType != type) {
@@ -704,9 +738,10 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
obs_service_t *service_obj = main->GetService(); obs_service_t *service_obj = main->GetService();
const char *protocol = obs_service_get_protocol(service_obj); const char *protocol = obs_service_get_protocol(service_obj);
if (protocol) { if (protocol) {
if (astrcmpi_n(protocol, RTMP_PROTOCOL, strlen(RTMP_PROTOCOL)) == 0) if (astrcmpi_n(protocol, RTMP_PROTOCOL, strlen(RTMP_PROTOCOL)) == 0) {
is_rtmp = true; is_rtmp = true;
} }
}
OBSDataAutoRelease settings = obs_data_create(); OBSDataAutoRelease settings = obs_data_create();
obs_data_set_string(settings, "bind_ip", bindIP); obs_data_set_string(settings, "bind_ip", bindIP);
@@ -721,8 +756,9 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
obs_output_update(streamOutput, settings); obs_output_update(streamOutput, settings);
if (!reconnect) if (!reconnect) {
maxRetries = 0; maxRetries = 0;
}
obs_output_set_delay(streamOutput, useDelay ? delaySec : 0, preserveDelay ? OBS_OUTPUT_DELAY_PRESERVE : 0); obs_output_set_delay(streamOutput, useDelay ? delaySec : 0, preserveDelay ? OBS_OUTPUT_DELAY_PRESERVE : 0);
@@ -731,20 +767,23 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service)
SetupVodTrack(service); SetupVodTrack(service);
} }
if (obs_output_start(streamOutput)) { if (obs_output_start(streamOutput)) {
if (multitrackVideo && multitrackVideoActive) if (multitrackVideo && multitrackVideoActive) {
multitrackVideo->StartedStreaming(); multitrackVideo->StartedStreaming();
}
return true; return true;
} }
if (multitrackVideo && multitrackVideoActive) if (multitrackVideo && multitrackVideoActive) {
multitrackVideoActive = false; multitrackVideoActive = false;
}
const char *error = obs_output_get_last_error(streamOutput); const char *error = obs_output_get_last_error(streamOutput);
bool hasLastError = error && *error; bool hasLastError = error && *error;
if (hasLastError) if (hasLastError) {
lastError = error; lastError = error;
else } else {
lastError = string(); lastError = string();
}
const char *type = obs_output_get_id(streamOutput); const char *type = obs_output_get_id(streamOutput);
blog(LOG_WARNING, "Stream output type '%s' failed to start!%s%s", type, hasLastError ? " Last Error: " : "", blog(LOG_WARNING, "Stream output type '%s' failed to start!%s%s", type, hasLastError ? " Last Error: " : "",
@@ -774,8 +813,9 @@ bool AdvancedOutput::StartRecording()
UpdateAudioSettings(); UpdateAudioSettings();
if (!Active()) if (!Active()) {
SetupOutputs(); SetupOutputs();
}
if (!ffmpegOutput || ffmpegRecording) { if (!ffmpegOutput || ffmpegRecording) {
path = config_get_string(main->Config(), "AdvOut", ffmpegRecording ? "FFFilePath" : "RecFilePath"); path = config_get_string(main->Config(), "AdvOut", ffmpegRecording ? "FFFilePath" : "RecFilePath");
@@ -817,10 +857,11 @@ bool AdvancedOutput::StartRecording()
if (!obs_output_start(fileOutput)) { if (!obs_output_start(fileOutput)) {
QString error_reason; QString error_reason;
const char *error = obs_output_get_last_error(fileOutput); const char *error = obs_output_get_last_error(fileOutput);
if (error) if (error) {
error_reason = QT_UTF8(error); error_reason = QT_UTF8(error);
else } else {
error_reason = QTStr("Output.StartFailedGeneric"); error_reason = QTStr("Output.StartFailedGeneric");
}
QMessageBox::critical(main, QTStr("Output.StartRecordingFailed"), error_reason); QMessageBox::critical(main, QTStr("Output.StartRecordingFailed"), error_reason);
return false; return false;
} }
@@ -841,16 +882,18 @@ bool AdvancedOutput::StartReplayBuffer()
int rbSize; int rbSize;
if (!useStreamEncoder) { if (!useStreamEncoder) {
if (!ffmpegOutput) if (!ffmpegOutput) {
UpdateRecordingSettings(); UpdateRecordingSettings();
}
} else if (!obs_output_active(StreamingOutput())) { } else if (!obs_output_active(StreamingOutput())) {
UpdateStreamSettings(); UpdateStreamSettings();
} }
UpdateAudioSettings(); UpdateAudioSettings();
if (!Active()) if (!Active()) {
SetupOutputs(); SetupOutputs();
}
if (!ffmpegOutput || ffmpegRecording) { if (!ffmpegOutput || ffmpegRecording) {
path = config_get_string(main->Config(), "AdvOut", ffmpegRecording ? "FFFilePath" : "RecFilePath"); path = config_get_string(main->Config(), "AdvOut", ffmpegRecording ? "FFFilePath" : "RecFilePath");
@@ -882,10 +925,11 @@ bool AdvancedOutput::StartReplayBuffer()
if (!obs_output_start(replayBuffer)) { if (!obs_output_start(replayBuffer)) {
QString error_reason; QString error_reason;
const char *error = obs_output_get_last_error(replayBuffer); const char *error = obs_output_get_last_error(replayBuffer);
if (error) if (error) {
error_reason = QT_UTF8(error); error_reason = QT_UTF8(error);
else } else {
error_reason = QTStr("Output.StartFailedGeneric"); error_reason = QTStr("Output.StartFailedGeneric");
}
QMessageBox::critical(main, QTStr("Output.StartReplayFailed"), error_reason); QMessageBox::critical(main, QTStr("Output.StartReplayFailed"), error_reason);
return false; return false;
} }
@@ -896,29 +940,32 @@ bool AdvancedOutput::StartReplayBuffer()
void AdvancedOutput::StopStreaming(bool force) void AdvancedOutput::StopStreaming(bool force)
{ {
auto output = StreamingOutput(); auto output = StreamingOutput();
if (force && output) if (force && output) {
obs_output_force_stop(output); obs_output_force_stop(output);
else if (multitrackVideo && multitrackVideoActive) } else if (multitrackVideo && multitrackVideoActive) {
multitrackVideo->StopStreaming(); multitrackVideo->StopStreaming();
else } else {
obs_output_stop(output); obs_output_stop(output);
} }
}
void AdvancedOutput::StopRecording(bool force) void AdvancedOutput::StopRecording(bool force)
{ {
if (force) if (force) {
obs_output_force_stop(fileOutput); obs_output_force_stop(fileOutput);
else } else {
obs_output_stop(fileOutput); obs_output_stop(fileOutput);
} }
}
void AdvancedOutput::StopReplayBuffer(bool force) void AdvancedOutput::StopReplayBuffer(bool force)
{ {
if (force) if (force) {
obs_output_force_stop(replayBuffer); obs_output_force_stop(replayBuffer);
else } else {
obs_output_stop(replayBuffer); obs_output_stop(replayBuffer);
} }
}
bool AdvancedOutput::StreamingActive() const bool AdvancedOutput::StreamingActive() const
{ {
+40 -21
View File
@@ -54,9 +54,10 @@ try {
json manifestContents = json::parse(manifest_data); json manifestContents = json::parse(manifest_data);
Manifest manifest = manifestContents.get<Manifest>(); Manifest manifest = manifestContents.get<Manifest>();
if (manifest.version_major == 0 && manifest.commit.empty()) if (manifest.version_major == 0 && manifest.commit.empty()) {
throw strprintf("Invalid version number: %d.%d.%d", manifest.version_major, manifest.version_minor, throw strprintf("Invalid version number: %d.%d.%d", manifest.version_major, manifest.version_minor,
manifest.version_patch); manifest.version_patch);
}
notes = manifest.notes; notes = manifest.notes;
@@ -67,19 +68,21 @@ try {
new_ver <<= 16; new_ver <<= 16;
/* RC builds are shifted so that rc1 and beta1 versions do not result /* RC builds are shifted so that rc1 and beta1 versions do not result
* in the same new_ver. */ * in the same new_ver. */
if (manifest.rc > 0) if (manifest.rc > 0) {
new_ver |= (uint64_t)manifest.rc << 8; new_ver |= (uint64_t)manifest.rc << 8;
else if (manifest.beta > 0) } else if (manifest.beta > 0) {
new_ver |= (uint64_t)manifest.beta; new_ver |= (uint64_t)manifest.beta;
}
updateVer = to_string(new_ver); updateVer = to_string(new_ver);
/* When using a pre-release build or non-default branch we only check if /* When using a pre-release build or non-default branch we only check if
* the manifest version is different, so that it can be rolled back. */ * the manifest version is different, so that it can be rolled back. */
if (branch != WIN_DEFAULT_BRANCH || isPreRelease) if (branch != WIN_DEFAULT_BRANCH || isPreRelease) {
*updatesAvailable = new_ver != currentVersion; *updatesAvailable = new_ver != currentVersion;
else } else {
*updatesAvailable = new_ver > currentVersion; *updatesAvailable = new_ver > currentVersion;
}
} else { } else {
/* Test or nightly builds may not have a (valid) version number, /* Test or nightly builds may not have a (valid) version number,
* so compare commit hashes instead. */ * so compare commit hashes instead. */
@@ -99,13 +102,15 @@ try {
bool GetBranchAndUrl(string &selectedBranch, string &manifestUrl) bool GetBranchAndUrl(string &selectedBranch, string &manifestUrl)
{ {
const char *config_branch = config_get_string(App()->GetAppConfig(), "General", "UpdateBranch"); const char *config_branch = config_get_string(App()->GetAppConfig(), "General", "UpdateBranch");
if (!config_branch) if (!config_branch) {
return true; return true;
}
bool found = false; bool found = false;
for (const UpdateBranch &branch : App()->GetBranches()) { for (const UpdateBranch &branch : App()->GetBranches()) {
if (branch.name != config_branch) if (branch.name != config_branch) {
continue; continue;
}
/* A branch that is found but disabled will just silently fall back to /* A branch that is found but disabled will just silently fall back to
* the default. But if the branch was removed entirely, the user should * the default. But if the branch was removed entirely, the user should
* be warned, so leave this false *only* if the branch was removed. */ * be warned, so leave this false *only* if the branch was removed. */
@@ -183,8 +188,9 @@ try {
/* ----------------------------------- * /* ----------------------------------- *
* get branches from server */ * get branches from server */
if (FetchAndVerifyFile("branches", "obs-studio\\updates\\branches.json", WIN_BRANCHES_URL, &text)) if (FetchAndVerifyFile("branches", "obs-studio\\updates\\branches.json", WIN_BRANCHES_URL, &text)) {
App()->SetBranchData(text); App()->SetBranchData(text);
}
/* ----------------------------------- * /* ----------------------------------- *
* check branch and get manifest url */ * check branch and get manifest url */
@@ -196,16 +202,18 @@ try {
/* allow server to know if this was a manual update check in case /* allow server to know if this was a manual update check in case
* we want to allow people to bypass a configured rollout rate */ * we want to allow people to bypass a configured rollout rate */
if (manualUpdate) if (manualUpdate) {
extraHeaders.emplace_back("X-OBS2-ManualUpdate: 1"); extraHeaders.emplace_back("X-OBS2-ManualUpdate: 1");
}
/* ----------------------------------- * /* ----------------------------------- *
* get manifest from server */ * get manifest from server */
text.clear(); text.clear();
if (!FetchAndVerifyFile("manifest", "obs-studio\\updates\\manifest.json", manifestUrl.c_str(), &text, if (!FetchAndVerifyFile("manifest", "obs-studio\\updates\\manifest.json", manifestUrl.c_str(), &text,
extraHeaders)) extraHeaders)) {
return; return;
}
/* ----------------------------------- * /* ----------------------------------- *
* check manifest for update */ * check manifest for update */
@@ -213,12 +221,14 @@ try {
string notes; string notes;
string updateVer; string updateVer;
if (!ParseUpdateManifest(text.c_str(), &updatesAvailable, notes, updateVer, branch)) if (!ParseUpdateManifest(text.c_str(), &updatesAvailable, notes, updateVer, branch)) {
throw string("Failed to parse manifest"); throw string("Failed to parse manifest");
}
if (!updatesAvailable && !repairMode) { if (!updatesAvailable && !repairMode) {
if (manualUpdate) if (manualUpdate) {
info(QTStr("Updater.NoUpdatesAvailable.Title"), QTStr("Updater.NoUpdatesAvailable.Text")); info(QTStr("Updater.NoUpdatesAvailable.Title"), QTStr("Updater.NoUpdatesAvailable.Text"));
}
return; return;
} else if (updatesAvailable && repairMode) { } else if (updatesAvailable && repairMode) {
info(QTStr("Updater.RepairButUpdatesAvailable.Title"), QTStr("Updater.RepairButUpdatesAvailable.Text")); info(QTStr("Updater.RepairButUpdatesAvailable.Title"), QTStr("Updater.RepairButUpdatesAvailable.Text"));
@@ -229,21 +239,24 @@ try {
* skip this version if set to skip */ * skip this version if set to skip */
const char *skipUpdateVer = config_get_string(App()->GetAppConfig(), "General", "SkipUpdateVersion"); const char *skipUpdateVer = config_get_string(App()->GetAppConfig(), "General", "SkipUpdateVersion");
if (!manualUpdate && !repairMode && skipUpdateVer && updateVer == skipUpdateVer) if (!manualUpdate && !repairMode && skipUpdateVer && updateVer == skipUpdateVer) {
return; return;
}
/* ----------------------------------- * /* ----------------------------------- *
* fetch updater module */ * fetch updater module */
if (!FetchAndVerifyFile("updater", "obs-studio\\updates\\updater.exe", WIN_UPDATER_URL, nullptr)) if (!FetchAndVerifyFile("updater", "obs-studio\\updates\\updater.exe", WIN_UPDATER_URL, nullptr)) {
return; return;
}
/* ----------------------------------- * /* ----------------------------------- *
* query user for update */ * query user for update */
if (repairMode) { if (repairMode) {
if (!queryRepair()) if (!queryRepair()) {
return; return;
}
} else { } else {
int queryResult = queryUpdate(manualUpdate, notes.c_str()); int queryResult = queryUpdate(manualUpdate, notes.c_str());
@@ -266,8 +279,9 @@ try {
wchar_t cwd[MAX_PATH]; wchar_t cwd[MAX_PATH];
GetModuleFileNameW(nullptr, cwd, _countof(cwd) - 1); GetModuleFileNameW(nullptr, cwd, _countof(cwd) - 1);
wchar_t *p = wcsrchr(cwd, '\\'); wchar_t *p = wcsrchr(cwd, '\\');
if (p) if (p) {
*p = 0; *p = 0;
}
/* ----------------------------------- * /* ----------------------------------- *
* execute updater */ * execute updater */
@@ -276,8 +290,9 @@ try {
BPtr<wchar_t> wUpdateFilePath; BPtr<wchar_t> wUpdateFilePath;
size_t size = os_utf8_to_wcs_ptr(updateFilePath, 0, &wUpdateFilePath); size_t size = os_utf8_to_wcs_ptr(updateFilePath, 0, &wUpdateFilePath);
if (!size) if (!size) {
throw string("Could not convert updateFilePath to wide"); throw string("Could not convert updateFilePath to wide");
}
/* note, can't use CreateProcess to launch as admin. */ /* note, can't use CreateProcess to launch as admin. */
SHELLEXECUTEINFO execInfo = {}; SHELLEXECUTEINFO execInfo = {};
@@ -286,13 +301,15 @@ try {
execInfo.lpFile = wUpdateFilePath; execInfo.lpFile = wUpdateFilePath;
string parameters; string parameters;
if (branch != WIN_DEFAULT_BRANCH) if (branch != WIN_DEFAULT_BRANCH) {
parameters += "--branch=" + branch; parameters += "--branch=" + branch;
}
obs_cmdline_args obs_args = obs_get_cmdline_args(); obs_cmdline_args obs_args = obs_get_cmdline_args();
for (int idx = 1; idx < obs_args.argc; idx++) { for (int idx = 1; idx < obs_args.argc; idx++) {
if (!parameters.empty()) if (!parameters.empty()) {
parameters += " "; parameters += " ";
}
parameters += obs_args.argv[idx]; parameters += obs_args.argv[idx];
} }
@@ -300,15 +317,17 @@ try {
/* Portable mode can be enabled via sentinel files, so copying the /* Portable mode can be enabled via sentinel files, so copying the
* command line doesn't guarantee the flag to be there. */ * command line doesn't guarantee the flag to be there. */
if (App()->IsPortableMode() && parameters.find("--portable") == string::npos) { if (App()->IsPortableMode() && parameters.find("--portable") == string::npos) {
if (!parameters.empty()) if (!parameters.empty()) {
parameters += " "; parameters += " ";
}
parameters += "--portable"; parameters += "--portable";
} }
BPtr<wchar_t> lpParameters; BPtr<wchar_t> lpParameters;
size = os_utf8_to_wcs_ptr(parameters.c_str(), 0, &lpParameters); size = os_utf8_to_wcs_ptr(parameters.c_str(), 0, &lpParameters);
if (!size && !parameters.empty()) if (!size && !parameters.empty()) {
throw string("Could not convert parameters to wide"); throw string("Could not convert parameters to wide");
}
execInfo.lpParameters = lpParameters; execInfo.lpParameters = lpParameters;
execInfo.lpDirectory = cwd; execInfo.lpDirectory = cwd;
+41 -21
View File
@@ -27,8 +27,9 @@ void OBSStreamStarting(void *data, calldata_t *params)
obs_output_t *obj = (obs_output_t *)calldata_ptr(params, "output"); obs_output_t *obj = (obs_output_t *)calldata_ptr(params, "output");
int sec = (int)obs_output_get_active_delay(obj); int sec = (int)obs_output_get_active_delay(obj);
if (sec == 0) if (sec == 0) {
return; return;
}
output->delayActive = true; output->delayActive = true;
QMetaObject::invokeMethod(output->main, "StreamDelayStarting", Q_ARG(int, sec)); QMetaObject::invokeMethod(output->main, "StreamDelayStarting", Q_ARG(int, sec));
@@ -40,11 +41,12 @@ void OBSStreamStopping(void *data, calldata_t *params)
obs_output_t *obj = (obs_output_t *)calldata_ptr(params, "output"); obs_output_t *obj = (obs_output_t *)calldata_ptr(params, "output");
int sec = (int)obs_output_get_active_delay(obj); int sec = (int)obs_output_get_active_delay(obj);
if (sec == 0) if (sec == 0) {
QMetaObject::invokeMethod(output->main, "StreamStopping"); QMetaObject::invokeMethod(output->main, "StreamStopping");
else } else {
QMetaObject::invokeMethod(output->main, "StreamDelayStopping", Q_ARG(int, sec)); QMetaObject::invokeMethod(output->main, "StreamDelayStopping", Q_ARG(int, sec));
} }
}
void OBSStartStreaming(void *data, calldata_t * /* params */) void OBSStartStreaming(void *data, calldata_t * /* params */)
{ {
@@ -192,8 +194,9 @@ const char *GetStreamOutputType(const obs_service_t *service)
/* Check if the service has a preferred output type */ /* Check if the service has a preferred output type */
output = obs_service_get_preferred_output_type(service); output = obs_service_get_preferred_output_type(service);
if (output) { if (output) {
if ((obs_get_output_flags(output) & OBS_OUTPUT_SERVICE) != 0) if ((obs_get_output_flags(output) & OBS_OUTPUT_SERVICE) != 0) {
return output; return output;
}
blog(LOG_WARNING, "The output '%s' is not registered, fallback to another one", output); blog(LOG_WARNING, "The output '%s' is not registered, fallback to another one", output);
} }
@@ -209,8 +212,9 @@ const char *GetStreamOutputType(const obs_service_t *service)
/* If third-party protocol, use the first enumerated type */ /* If third-party protocol, use the first enumerated type */
obs_enum_output_types_with_protocol(protocol, &output, return_first_id); obs_enum_output_types_with_protocol(protocol, &output, return_first_id);
if (output) if (output) {
return output; return output;
}
blog(LOG_WARNING, "No output compatible with the service '%s' is registered", obs_service_get_id(service)); blog(LOG_WARNING, "No output compatible with the service '%s' is registered", obs_service_get_id(service));
@@ -234,37 +238,43 @@ BasicOutputHandler::BasicOutputHandler(OBSBasic *main_) : main(main_)
(obs_data_has_user_value(settings, "multitrack_video_configuration_url") || (obs_data_has_user_value(settings, "multitrack_video_configuration_url") ||
strcmp(obs_service_get_id(service), "rtmp_custom") == 0); strcmp(obs_service_get_id(service), "rtmp_custom") == 0);
if (multitrack_enabled) if (multitrack_enabled) {
multitrackVideo = make_unique<MultitrackVideoOutput>(); multitrackVideo = make_unique<MultitrackVideoOutput>();
}
if (config_get_int(main->Config(), "Stream1", "WHIPSimulcastTotalLayers") > 1) if (config_get_int(main->Config(), "Stream1", "WHIPSimulcastTotalLayers") > 1) {
whipSimulcastEncoders = make_unique<WHIPSimulcastEncoders>(); whipSimulcastEncoders = make_unique<WHIPSimulcastEncoders>();
} }
}
extern void log_vcam_changed(const VCamConfig &config, bool starting); extern void log_vcam_changed(const VCamConfig &config, bool starting);
bool BasicOutputHandler::StartVirtualCam() bool BasicOutputHandler::StartVirtualCam()
{ {
if (!main->vcamEnabled) if (!main->vcamEnabled) {
return false; return false;
}
bool typeIsProgram = main->vcamConfig.type == VCamOutputType::ProgramView; bool typeIsProgram = main->vcamConfig.type == VCamOutputType::ProgramView;
if (!virtualCamView && !typeIsProgram) if (!virtualCamView && !typeIsProgram) {
virtualCamView = obs_view_create(); virtualCamView = obs_view_create();
}
UpdateVirtualCamOutputSource(); UpdateVirtualCamOutputSource();
if (!virtualCamVideo) { if (!virtualCamVideo) {
virtualCamVideo = typeIsProgram ? obs_get_video() : obs_view_add(virtualCamView); virtualCamVideo = typeIsProgram ? obs_get_video() : obs_view_add(virtualCamView);
if (!virtualCamVideo) if (!virtualCamVideo) {
return false; return false;
} }
}
obs_output_set_media(virtualCam, virtualCamVideo, obs_get_audio()); obs_output_set_media(virtualCam, virtualCamVideo, obs_get_audio());
if (!Active()) if (!Active()) {
SetupOutputs(); SetupOutputs();
}
bool success = obs_output_start(virtualCam); bool success = obs_output_start(virtualCam);
if (!success) { if (!success) {
@@ -304,8 +314,9 @@ bool BasicOutputHandler::VirtualCamActive() const
void BasicOutputHandler::UpdateVirtualCamOutputSource() void BasicOutputHandler::UpdateVirtualCamOutputSource()
{ {
if (!main->vcamEnabled || !virtualCamView) if (!main->vcamEnabled || !virtualCamView) {
return; return;
}
OBSSourceAutoRelease source; OBSSourceAutoRelease source;
@@ -328,8 +339,9 @@ void BasicOutputHandler::UpdateVirtualCamOutputSource()
case VCamOutputType::SourceOutput: case VCamOutputType::SourceOutput:
OBSSourceAutoRelease s = obs_get_source_by_name(main->vcamConfig.source.c_str()); OBSSourceAutoRelease s = obs_get_source_by_name(main->vcamConfig.source.c_str());
if (!vCamSourceScene) if (!vCamSourceScene) {
vCamSourceScene = obs_scene_create_private("vcam_source"); vCamSourceScene = obs_scene_create_private("vcam_source");
}
source = obs_source_get_ref(obs_scene_get_source(vCamSourceScene)); source = obs_source_get_ref(obs_scene_get_source(vCamSourceScene));
if (vCamSourceSceneItem && (obs_sceneitem_get_source(vCamSourceSceneItem) != s)) { if (vCamSourceSceneItem && (obs_sceneitem_get_source(vCamSourceSceneItem) != s)) {
@@ -353,9 +365,10 @@ void BasicOutputHandler::UpdateVirtualCamOutputSource()
} }
OBSSourceAutoRelease current = obs_view_get_source(virtualCamView, 0); OBSSourceAutoRelease current = obs_view_get_source(virtualCamView, 0);
if (source != current) if (source != current) {
obs_view_set_source(virtualCamView, 0, source); obs_view_set_source(virtualCamView, 0, source);
} }
}
void BasicOutputHandler::DestroyVirtualCamView() void BasicOutputHandler::DestroyVirtualCamView()
{ {
@@ -376,8 +389,9 @@ void BasicOutputHandler::DestroyVirtualCamView()
void BasicOutputHandler::DestroyVirtualCameraScene() void BasicOutputHandler::DestroyVirtualCameraScene()
{ {
if (!vCamSourceScene) if (!vCamSourceScene) {
return; return;
}
obs_scene_release(vCamSourceScene); obs_scene_release(vCamSourceScene);
vCamSourceScene = nullptr; vCamSourceScene = nullptr;
@@ -411,22 +425,25 @@ void clear_archive_encoder(obs_output_t *output, const char *expected_name)
obs_encoder_release(last); obs_encoder_release(last);
} }
if (clear) if (clear) {
obs_output_set_audio_encoder(output, nullptr, 1); obs_output_set_audio_encoder(output, nullptr, 1);
} }
}
void BasicOutputHandler::SetupAutoRemux(const char *&container) void BasicOutputHandler::SetupAutoRemux(const char *&container)
{ {
bool autoRemux = config_get_bool(main->Config(), "Video", "AutoRemux"); bool autoRemux = config_get_bool(main->Config(), "Video", "AutoRemux");
if (autoRemux && strcmp(container, "mp4") == 0) if (autoRemux && strcmp(container, "mp4") == 0) {
container = "mkv"; container = "mkv";
} }
}
std::string BasicOutputHandler::GetRecordingFilename(const char *path, const char *container, bool noSpace, std::string BasicOutputHandler::GetRecordingFilename(const char *path, const char *container, bool noSpace,
bool overwrite, const char *format, bool ffmpeg) bool overwrite, const char *format, bool ffmpeg)
{ {
if (!ffmpeg) if (!ffmpeg) {
SetupAutoRemux(container); SetupAutoRemux(container);
}
string dst = GetOutputFilename(path, container, noSpace, overwrite, format); string dst = GetOutputFilename(path, container, noSpace, overwrite, format);
lastRecordingPath = dst; lastRecordingPath = dst;
@@ -456,9 +473,10 @@ std::shared_future<void> BasicOutputHandler::SetupMultitrackVideo(obs_service_t
bool is_custom = strncmp("rtmp_custom", obs_service_get_type(service), 11) == 0; bool is_custom = strncmp("rtmp_custom", obs_service_get_type(service), 11) == 0;
std::optional<std::string> custom_config = std::nullopt; std::optional<std::string> custom_config = std::nullopt;
if (config_get_bool(main->Config(), "Stream1", "MultitrackVideoConfigOverrideEnabled")) if (config_get_bool(main->Config(), "Stream1", "MultitrackVideoConfigOverrideEnabled")) {
custom_config = DeserializeConfigText( custom_config = DeserializeConfigText(
config_get_string(main->Config(), "Stream1", "MultitrackVideoConfigOverride")); config_get_string(main->Config(), "Stream1", "MultitrackVideoConfigOverride"));
}
std::optional<QString> extraCanvasUUID; std::optional<QString> extraCanvasUUID;
const char *uuid = config_get_string(main->Config(), "Stream1", "MultitrackExtraCanvas"); const char *uuid = config_get_string(main->Config(), "Stream1", "MultitrackExtraCanvas");
@@ -515,8 +533,9 @@ std::shared_future<void> BasicOutputHandler::SetupMultitrackVideo(obs_service_t
} }
multitrackVideoActive = false; multitrackVideoActive = false;
if (!error->ShowDialog(main, multitrack_video_name)) if (!error->ShowDialog(main, multitrack_video_name)) {
return continuation(false); return continuation(false);
}
return continuation(std::nullopt); return continuation(std::nullopt);
} }
@@ -557,8 +576,9 @@ OBSDataAutoRelease BasicOutputHandler::GenerateMultitrackVideoStreamDumpConfig()
{ {
auto stream_dump_enabled = config_get_bool(main->Config(), "Stream1", "MultitrackVideoStreamDumpEnabled"); auto stream_dump_enabled = config_get_bool(main->Config(), "Stream1", "MultitrackVideoStreamDumpEnabled");
if (!stream_dump_enabled) if (!stream_dump_enabled) {
return nullptr; return nullptr;
}
const char *path = config_get_string(main->Config(), "SimpleOutput", "FilePath"); const char *path = config_get_string(main->Config(), "SimpleOutput", "FilePath");
bool noSpace = config_get_bool(main->Config(), "SimpleOutput", "FileNameWithoutSpace"); bool noSpace = config_get_bool(main->Config(), "SimpleOutput", "FileNameWithoutSpace");
+2 -1
View File
@@ -139,9 +139,10 @@ inline bool ServiceSupportsVodTrack(const char *service)
static const char *vodTrackServices[] = {"Twitch"}; static const char *vodTrackServices[] = {"Twitch"};
for (const char *vodTrackService : vodTrackServices) { for (const char *vodTrackService : vodTrackServices) {
if (astrcmpi(vodTrackService, service) == 0) if (astrcmpi(vodTrackService, service) == 0) {
return true; return true;
} }
}
return false; return false;
} }
+2 -1
View File
@@ -30,8 +30,9 @@ void ExtraBrowsersDelegate::setEditorData(QWidget *editor, const QModelIndex &in
bool ExtraBrowsersDelegate::eventFilter(QObject *object, QEvent *event) bool ExtraBrowsersDelegate::eventFilter(QObject *object, QEvent *event)
{ {
QLineEdit *edit = qobject_cast<QLineEdit *>(object); QLineEdit *edit = qobject_cast<QLineEdit *>(object);
if (!edit) if (!edit) {
return false; return false;
}
if (LineEditCanceled(event)) { if (LineEditCanceled(event)) {
RevertText(edit); RevertText(edit);
+10 -5
View File
@@ -43,8 +43,9 @@ QVariant ExtraBrowsersModel::data(const QModelIndex &index, int role) const
int count = items.size(); int count = items.size();
bool validRole = role == Qt::DisplayRole || role == Qt::AccessibleTextRole; bool validRole = role == Qt::DisplayRole || role == Qt::AccessibleTextRole;
if (!validRole) if (!validRole) {
return QVariant(); return QVariant();
}
if (idx >= 0 && idx < count) { if (idx >= 0 && idx < count) {
switch (column) { switch (column) {
@@ -85,8 +86,9 @@ Qt::ItemFlags ExtraBrowsersModel::flags(const QModelIndex &index) const
{ {
Qt::ItemFlags flags = QAbstractTableModel::flags(index); Qt::ItemFlags flags = QAbstractTableModel::flags(index);
if (index.column() != (int)Column::Delete) if (index.column() != (int)Column::Delete) {
flags |= Qt::ItemIsEditable; flags |= Qt::ItemIsEditable;
}
return flags; return flags;
} }
@@ -109,8 +111,9 @@ void ExtraBrowsersModel::AddDeleteButton(int idx)
void ExtraBrowsersModel::CheckToAdd() void ExtraBrowsersModel::CheckToAdd()
{ {
if (newTitle.isEmpty() || newURL.isEmpty()) if (newTitle.isEmpty() || newURL.isEmpty()) {
return; return;
}
int idx = items.size() + 1; int idx = items.size() + 1;
beginInsertRows(QModelIndex(), idx, idx); beginInsertRows(QModelIndex(), idx, idx);
@@ -201,8 +204,9 @@ void ExtraBrowsersModel::Apply()
main->extraBrowserDocks.removeAt(idx); main->extraBrowserDocks.removeAt(idx);
} }
if (main->extraBrowserDocks.empty()) if (main->extraBrowserDocks.empty()) {
main->extraBrowserMenuDocksSeparator.clear(); main->extraBrowserMenuDocksSeparator.clear();
}
deleted.clear(); deleted.clear();
@@ -249,6 +253,7 @@ void ExtraBrowsersModel::TabSelection(bool forward)
void ExtraBrowsersModel::Init() void ExtraBrowsersModel::Init()
{ {
for (int i = 0; i < items.count(); i++) for (int i = 0; i < items.count(); i++) {
AddDeleteButton(i); AddDeleteButton(i);
} }
}
+12 -6
View File
@@ -31,8 +31,9 @@ vector<FFmpegCodec> GetFormatCodecs(const FFmpegFormat &format, bool ignore_comp
while ((codec = av_codec_iterate(&i)) != nullptr) { while ((codec = av_codec_iterate(&i)) != nullptr) {
// Not an encoding codec // Not an encoding codec
if (!av_codec_is_encoder(codec)) if (!av_codec_is_encoder(codec)) {
continue; continue;
}
// Skip if not supported and compatibility check not disabled // Skip if not supported and compatibility check not disabled
if (!ignore_compatibility && !av_codec_get_tag(format.codec_tags, codec->id)) { if (!ignore_compatibility && !av_codec_get_tag(format.codec_tags, codec->id)) {
continue; continue;
@@ -46,16 +47,19 @@ vector<FFmpegCodec> GetFormatCodecs(const FFmpegFormat &format, bool ignore_comp
bool FFCodecAndFormatCompatible(const char *codec, const char *format) bool FFCodecAndFormatCompatible(const char *codec, const char *format)
{ {
if (!codec || !format) if (!codec || !format) {
return false; return false;
}
const AVOutputFormat *output_format = av_guess_format(format, nullptr, nullptr); const AVOutputFormat *output_format = av_guess_format(format, nullptr, nullptr);
if (!output_format) if (!output_format) {
return false; return false;
}
const AVCodecDescriptor *codec_desc = avcodec_descriptor_get_by_name(codec); const AVCodecDescriptor *codec_desc = avcodec_descriptor_get_by_name(codec);
if (!codec_desc) if (!codec_desc) {
return false; return false;
}
return avformat_query_codec(output_format, codec_desc->id, FF_COMPLIANCE_NORMAL) == 1; return avformat_query_codec(output_format, codec_desc->id, FF_COMPLIANCE_NORMAL) == 1;
} }
@@ -171,13 +175,15 @@ static const unordered_map<string, unordered_set<string>> codec_compat = {
bool ContainerSupportsCodec(const string &container, const string &codec) bool ContainerSupportsCodec(const string &container, const string &codec)
{ {
auto iter = codec_compat.find(container); auto iter = codec_compat.find(container);
if (iter == codec_compat.end()) if (iter == codec_compat.end()) {
return false; return false;
}
auto codecs = iter->second; auto codecs = iter->second;
// Assume everything is supported // Assume everything is supported
if (codecs.empty()) if (codecs.empty()) {
return true; return true;
}
return codecs.count(codec) > 0; return codecs.count(codec) > 0;
} }
+2 -1
View File
@@ -60,8 +60,9 @@ struct FFmpegCodec {
bool operator==(const FFmpegCodec &codec) const bool operator==(const FFmpegCodec &codec) const
{ {
if (id != codec.id) if (id != codec.id) {
return false; return false;
}
return strequal(name, codec.name); return strequal(name, codec.name);
} }
+8 -4
View File
@@ -22,8 +22,9 @@ using namespace std;
static bool is_output_device(const AVClass *avclass) static bool is_output_device(const AVClass *avclass)
{ {
if (!avclass) if (!avclass) {
return false; return false;
}
switch (avclass->category) { switch (avclass->category) {
case AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT: case AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT:
@@ -42,8 +43,9 @@ vector<FFmpegFormat> GetSupportedFormats()
void *i = 0; void *i = 0;
while ((output_format = av_muxer_iterate(&i)) != nullptr) { while ((output_format = av_muxer_iterate(&i)) != nullptr) {
if (is_output_device(output_format->priv_class)) if (is_output_device(output_format->priv_class)) {
continue; continue;
}
formats.emplace_back(output_format); formats.emplace_back(output_format);
} }
@@ -54,11 +56,13 @@ vector<FFmpegFormat> GetSupportedFormats()
FFmpegCodec FFmpegFormat::GetDefaultEncoder(FFmpegCodecType codec_type) const FFmpegCodec FFmpegFormat::GetDefaultEncoder(FFmpegCodecType codec_type) const
{ {
const AVCodecID codec_id = codec_type == VIDEO ? video_codec : audio_codec; const AVCodecID codec_id = codec_type == VIDEO ? video_codec : audio_codec;
if (codec_type == UNKNOWN || codec_id == AV_CODEC_ID_NONE) if (codec_type == UNKNOWN || codec_id == AV_CODEC_ID_NONE) {
return {}; return {};
}
if (auto codec = avcodec_find_encoder(codec_id)) if (auto codec = avcodec_find_encoder(codec_id)) {
return {codec}; return {codec};
}
/* Fall back to using the format name as the encoder, /* Fall back to using the format name as the encoder,
* this works for some formats such as FLV. */ * this works for some formats such as FLV. */
+2 -1
View File
@@ -67,8 +67,9 @@ struct FFmpegFormat {
bool operator==(const FFmpegFormat &format) const bool operator==(const FFmpegFormat &format) const
{ {
if (!strequal(name, format.name)) if (!strequal(name, format.name)) {
return false; return false;
}
return strequal(mime_type, format.mime_type); return strequal(mime_type, format.mime_type);
} }
+8 -4
View File
@@ -28,14 +28,18 @@ enum FFmpegCodecType { AUDIO, VIDEO, UNKNOWN };
*/ */
static bool strequal(const char *a, const char *b) static bool strequal(const char *a, const char *b)
{ {
if (!a && !b) if (!a && !b) {
return true; return true;
if (!a && *b == 0) }
if (!a && *b == 0) {
return true; return true;
if (!b && *a == 0) }
if (!b && *a == 0) {
return true; return true;
if (!a || !b) }
if (!a || !b) {
return false; return false;
}
return strcmp(a, b) == 0; return strcmp(a, b) == 0;
} }
+2 -1
View File
@@ -67,8 +67,9 @@ using json = nlohmann::json;
void censorRecurse(json &data) void censorRecurse(json &data)
{ {
if (!data.is_structured()) if (!data.is_structured()) {
return; return;
}
auto it = data.find("authentication"); auto it = data.find("authentication");
if (it != data.end() && it->is_string()) { if (it != data.end() && it->is_string()) {
+10 -5
View File
@@ -22,12 +22,14 @@ void HandleGoLiveApiErrors(QWidget *parent, const json &raw_json, const GoLiveAp
{ {
using GoLiveApi::StatusResult; using GoLiveApi::StatusResult;
if (!config.status) if (!config.status) {
return; return;
}
auto &status = *config.status; auto &status = *config.status;
if (status.result == StatusResult::Success) if (status.result == StatusResult::Success) {
return; return;
}
auto warn_continue = [&](QString message) { auto warn_continue = [&](QString message) {
bool ret = false; bool ret = false;
@@ -44,8 +46,9 @@ void HandleGoLiveApiErrors(QWidget *parent, const json &raw_json, const GoLiveAp
return mb.exec() == QMessageBox::StandardButton::No; return mb.exec() == QMessageBox::StandardButton::No;
}, },
BlockingConnectionTypeFor(parent), &ret); BlockingConnectionTypeFor(parent), &ret);
if (ret) if (ret) {
throw MultitrackVideoError::cancel(); throw MultitrackVideoError::cancel();
}
}; };
auto missing_html = [] { auto missing_html = [] {
@@ -73,8 +76,9 @@ GoLiveApi::Config DownloadGoLiveConfig(QWidget *parent, QString url, const GoLiv
json post_data_json = post_data; json post_data_json = post_data;
blog(LOG_INFO, "Go live POST data: %s", censoredJson(post_data_json).toUtf8().constData()); blog(LOG_INFO, "Go live POST data: %s", censoredJson(post_data_json).toUtf8().constData());
if (url.isEmpty()) if (url.isEmpty()) {
throw MultitrackVideoError::critical(QTStr("FailedToStartStream.MissingConfigURL")); throw MultitrackVideoError::critical(QTStr("FailedToStartStream.MissingConfigURL"));
}
std::string encodeConfigText; std::string encodeConfigText;
std::string libraryError; std::string libraryError;
@@ -89,9 +93,10 @@ GoLiveApi::Config DownloadGoLiveConfig(QWidget *parent, QString url, const GoLiv
nullptr, // signature nullptr, // signature
5); // timeout in seconds 5); // timeout in seconds
if (!encodeConfigDownloadedOk) if (!encodeConfigDownloadedOk) {
throw MultitrackVideoError::warning( throw MultitrackVideoError::warning(
QTStr("FailedToStartStream.ConfigRequestFailed").arg(url, libraryError.c_str())); QTStr("FailedToStartStream.ConfigRequestFailed").arg(url, libraryError.c_str()));
}
try { try {
auto data = json::parse(encodeConfigText); auto data = json::parse(encodeConfigText);
blog(LOG_INFO, "Go live response data: %s", censoredJson(data, true).toUtf8().constData()); blog(LOG_INFO, "Go live response data: %s", censoredJson(data, true).toUtf8().constData());
+6 -3
View File
@@ -24,8 +24,9 @@ GoLiveApi::PostData constructGoLivePost(QString streamKey, const std::optional<u
const char *encoder_id = nullptr; const char *encoder_id = nullptr;
for (size_t i = 0; obs_enum_encoder_types(i, &encoder_id); i++) { for (size_t i = 0; obs_enum_encoder_types(i, &encoder_id); i++) {
auto codec = obs_get_encoder_codec(encoder_id); auto codec = obs_get_encoder_codec(encoder_id);
if (!codec) if (!codec) {
continue; continue;
}
if (qstricmp(codec, "h264") == 0) { if (qstricmp(codec, "h264") == 0) {
client.supported_codecs.emplace("h264"); client.supported_codecs.emplace("h264");
@@ -42,8 +43,9 @@ GoLiveApi::PostData constructGoLivePost(QString streamKey, const std::optional<u
preferences.vod_track_audio = vod_track_enabled; preferences.vod_track_audio = vod_track_enabled;
obs_video_info ovi; obs_video_info ovi;
if (obs_get_video_info(&ovi)) if (obs_get_video_info(&ovi)) {
preferences.composition_gpu_index = ovi.adapter; preferences.composition_gpu_index = ovi.adapter;
}
for (const auto &canvas : canvases) { for (const auto &canvas : canvases) {
if (obs_canvas_get_video_info(canvas, &ovi)) { if (obs_canvas_get_video_info(canvas, &ovi)) {
@@ -63,8 +65,9 @@ GoLiveApi::PostData constructGoLivePost(QString streamKey, const std::optional<u
preferences.audio_max_buffering_ms = oai2.max_buffering_ms; preferences.audio_max_buffering_ms = oai2.max_buffering_ms;
} }
if (maximum_aggregate_bitrate.has_value()) if (maximum_aggregate_bitrate.has_value()) {
preferences.maximum_aggregate_bitrate = maximum_aggregate_bitrate.value(); preferences.maximum_aggregate_bitrate = maximum_aggregate_bitrate.value();
}
if (maximum_video_tracks.has_value()) { if (maximum_video_tracks.has_value()) {
/* Cap to maximum supported number of output encoders. */ /* Cap to maximum supported number of output encoders. */
+6 -3
View File
@@ -13,13 +13,15 @@ static const char *MAC_DEFAULT_BRANCH = "stable";
bool GetBranch(std::string &selectedBranch) bool GetBranch(std::string &selectedBranch)
{ {
const char *config_branch = config_get_string(App()->GetAppConfig(), "General", "UpdateBranch"); const char *config_branch = config_get_string(App()->GetAppConfig(), "General", "UpdateBranch");
if (!config_branch) if (!config_branch) {
return true; return true;
}
bool found = false; bool found = false;
for (const UpdateBranch &branch : App()->GetBranches()) { for (const UpdateBranch &branch : App()->GetBranches()) {
if (branch.name != config_branch) if (branch.name != config_branch) {
continue; continue;
}
/* A branch that is found but disabled will just silently fall back to /* A branch that is found but disabled will just silently fall back to
* the default. But if the branch was removed entirely, the user should * the default. But if the branch was removed entirely, the user should
* be warned, so leave this false *only* if the branch was removed. */ * be warned, so leave this false *only* if the branch was removed. */
@@ -53,8 +55,9 @@ try {
/* ----------------------------------- * /* ----------------------------------- *
* get branches from server */ * get branches from server */
if (FetchAndVerifyFile("branches", "obs-studio/updates/branches.json", MAC_BRANCHES_URL, &text)) if (FetchAndVerifyFile("branches", "obs-studio/updates/branches.json", MAC_BRANCHES_URL, &text)) {
App()->SetBranchData(text); App()->SetBranchData(text);
}
/* ----------------------------------- * /* ----------------------------------- *
* Validate branch selection */ * Validate branch selection */
+4 -2
View File
@@ -46,9 +46,10 @@ int MissingFilesModel::found() const
int res = 0; int res = 0;
for (int i = 0; i < files.length(); i++) { for (int i = 0; i < files.length(); i++) {
if (files[i].state != Missing && files[i].state != Cleared) if (files[i].state != Missing && files[i].state != Cleared) {
res++; res++;
} }
}
return res; return res;
} }
@@ -213,8 +214,9 @@ void MissingFilesModel::fileCheckLoop(const QString &path, bool skipPrompt, int
os_dir_t *folder = os_opendir(dir.toStdString().c_str()); os_dir_t *folder = os_opendir(dir.toStdString().c_str());
struct os_dirent *ent; struct os_dirent *ent;
while ((ent = os_readdir(folder)) != NULL) { while ((ent = os_readdir(folder)) != NULL) {
if (!ent->directory || *ent->d_name == '.') if (!ent->directory || *ent->d_name == '.') {
continue; continue;
}
QString directoryPath = dir + QString(ent->d_name) + "/"; QString directoryPath = dir + QString(ent->d_name) + "/";
fileCheckLoop(directoryPath, true, depthWithoutFileMatch); fileCheckLoop(directoryPath, true, depthWithoutFileMatch);
@@ -128,8 +128,9 @@ void MissingFilesPathItemDelegate::handleBrowse(QWidget *container)
QLineEdit *text = container->findChild<QLineEdit *>(); QLineEdit *text = container->findChild<QLineEdit *>();
QString currentPath = text->text(); QString currentPath = text->text();
if (currentPath.isEmpty() || currentPath.compare(QTStr("MissingFiles.Clear")) == 0) if (currentPath.isEmpty() || currentPath.compare(QTStr("MissingFiles.Clear")) == 0) {
currentPath = ""; currentPath = "";
}
bool isSet = false; bool isSet = false;
@@ -146,9 +147,10 @@ void MissingFilesPathItemDelegate::handleBrowse(QWidget *container)
isSet = true; isSet = true;
} }
if (isSet) if (isSet) {
emit commitData(container); emit commitData(container);
} }
}
void MissingFilesPathItemDelegate::handleClear(QWidget *container) void MissingFilesPathItemDelegate::handleClear(QWidget *container)
{ {
+64 -32
View File
@@ -50,11 +50,13 @@ static OBSServiceAutoRelease create_service(const GoLiveApi::Config &go_live_con
const auto &ingest_endpoints = go_live_config.ingest_endpoints; const auto &ingest_endpoints = go_live_config.ingest_endpoints;
for (auto &endpoint : ingest_endpoints) { for (auto &endpoint : ingest_endpoints) {
if (qstrnicmp("RTMP", endpoint.protocol.c_str(), 4)) if (qstrnicmp("RTMP", endpoint.protocol.c_str(), 4)) {
continue; continue;
}
if (use_rtmps.has_value() && *use_rtmps != (qstricmp("RTMPS", endpoint.protocol.c_str()) == 0)) if (use_rtmps.has_value() && *use_rtmps != (qstricmp("RTMPS", endpoint.protocol.c_str()) == 0)) {
continue; continue;
}
url = endpoint.url_template.c_str(); url = endpoint.url_template.c_str();
if (endpoint.authentication && !endpoint.authentication->empty()) { if (endpoint.authentication && !endpoint.authentication->empty()) {
@@ -88,9 +90,10 @@ static OBSServiceAutoRelease create_service(const GoLiveApi::Config &go_live_con
// not initialize str if cat'ing with a null url // not initialize str if cat'ing with a null url
if (!dstr_is_empty(str)) { if (!dstr_is_empty(str)) {
auto found = dstr_find(str, "/{stream_key}"); auto found = dstr_find(str, "/{stream_key}");
if (found) if (found) {
dstr_remove(str, found - str->array, str->len - (found - str->array)); dstr_remove(str, found - str->array, str->len - (found - str->array));
} }
}
/* The stream key itself may contain query parameters, such as /* The stream key itself may contain query parameters, such as
* "bandwidthtest" that need to be carried over. */ * "bandwidthtest" that need to be carried over. */
@@ -102,8 +105,9 @@ static OBSServiceAutoRelease create_service(const GoLiveApi::Config &go_live_con
QUrl parsed_url{url}; QUrl parsed_url{url};
QUrlQuery parsed_query{parsed_url}; QUrlQuery parsed_query{parsed_url};
for (const auto &[key, value] : user_key_query.queryItems()) for (const auto &[key, value] : user_key_query.queryItems()) {
parsed_query.addQueryItem(key, value); parsed_query.addQueryItem(key, value);
}
if (!go_live_config.meta.config_id.empty()) { if (!go_live_config.meta.config_id.empty()) {
parsed_query.addQueryItem("clientConfigId", QString::fromStdString(go_live_config.meta.config_id)); parsed_query.addQueryItem("clientConfigId", QString::fromStdString(go_live_config.meta.config_id));
@@ -193,12 +197,14 @@ static void adjust_encoder_frame_rate_divisor(const obs_video_info &ovi, obs_enc
} }
media_frames_per_second requested_fps = *encoder_config.framerate; media_frames_per_second requested_fps = *encoder_config.framerate;
if (ovi.fps_num == requested_fps.numerator && ovi.fps_den == requested_fps.denominator) if (ovi.fps_num == requested_fps.numerator && ovi.fps_den == requested_fps.denominator) {
return; return;
}
auto divisor = closest_divisor(ovi, requested_fps); auto divisor = closest_divisor(ovi, requested_fps);
if (divisor <= 1) if (divisor <= 1) {
return; return;
}
blog(LOG_INFO, "Setting frame rate divisor to %u for encoder %zu", divisor, encoder_index); blog(LOG_INFO, "Setting frame rate divisor to %u for encoder %zu", divisor, encoder_index);
obs_encoder_set_frame_rate_divisor(video_encoder, divisor); obs_encoder_set_frame_rate_divisor(video_encoder, divisor);
@@ -209,9 +215,10 @@ static bool encoder_available(const char *type)
const char *id = nullptr; const char *id = nullptr;
for (size_t idx = 0; obs_enum_encoder_types(idx, &id); idx++) { for (size_t idx = 0; obs_enum_encoder_types(idx, &id); idx++) {
if (strcmp(id, type) == 0) if (strcmp(id, type) == 0) {
return true; return true;
} }
}
return false; return false;
} }
@@ -381,15 +388,17 @@ void MultitrackVideoOutput::PrepareStreaming(
std::string canvasNames; std::string canvasNames;
for (const auto &canvas : canvases) { for (const auto &canvas : canvases) {
if (!canvasNames.empty()) if (!canvasNames.empty()) {
canvasNames += ", "; canvasNames += ", ";
}
canvasNames += obs_canvas_get_name(canvas); canvasNames += obs_canvas_get_name(canvas);
} }
DStr vod_track_info_storage; DStr vod_track_info_storage;
if (vod_track_mixer.has_value()) if (vod_track_mixer.has_value()) {
dstr_printf(vod_track_info_storage, "Yes (mixer: %zu)", vod_track_mixer.value()); dstr_printf(vod_track_info_storage, "Yes (mixer: %zu)", vod_track_mixer.value());
}
blog(LOG_INFO, blog(LOG_INFO,
"Preparing enhanced broadcasting stream for:\n" "Preparing enhanced broadcasting stream for:\n"
@@ -464,14 +473,16 @@ void MultitrackVideoOutput::PrepareStreaming(
vod_track_mixer, canvases); vod_track_mixer, canvases);
auto output = std::move(outputs.output); auto output = std::move(outputs.output);
auto recording_output = std::move(outputs.recording_output); auto recording_output = std::move(outputs.recording_output);
if (!output) if (!output) {
throw MultitrackVideoError::warning( throw MultitrackVideoError::warning(
QTStr("FailedToStartStream.FallbackToDefault").arg(multitrack_video_name)); QTStr("FailedToStartStream.FallbackToDefault").arg(multitrack_video_name));
}
auto multitrack_video_service = create_service(service_config, rtmp_url, stream_key, use_rtmps); auto multitrack_video_service = create_service(service_config, rtmp_url, stream_key, use_rtmps);
if (!multitrack_video_service) if (!multitrack_video_service) {
throw MultitrackVideoError::warning( throw MultitrackVideoError::warning(
QTStr("FailedToStartStream.FallbackToDefault").arg(multitrack_video_name)); QTStr("FailedToStartStream.FallbackToDefault").arg(multitrack_video_name));
}
obs_output_set_service(output, multitrack_video_service); obs_output_set_service(output, multitrack_video_service);
@@ -547,8 +558,9 @@ void MultitrackVideoOutput::StartedStreaming()
} }
} }
if (!dump_output) if (!dump_output) {
return; return;
}
auto result = obs_output_start(dump_output); auto result = obs_output_start(dump_output);
blog(LOG_INFO, "MultitrackVideoOutput: starting recording%s", result ? "" : " failed"); blog(LOG_INFO, "MultitrackVideoOutput: starting recording%s", result ? "" : " failed");
@@ -561,21 +573,25 @@ void MultitrackVideoOutput::StopStreaming()
OBSOutputAutoRelease current_output; OBSOutputAutoRelease current_output;
{ {
const std::lock_guard current_lock{current_mutex}; const std::lock_guard current_lock{current_mutex};
if (current && current->output_) if (current && current->output_) {
current_output = obs_output_get_ref(current->output_); current_output = obs_output_get_ref(current->output_);
} }
if (current_output) }
if (current_output) {
obs_output_stop(current_output); obs_output_stop(current_output);
}
OBSOutputAutoRelease dump_output; OBSOutputAutoRelease dump_output;
{ {
const std::lock_guard current_stream_dump_lock{current_stream_dump_mutex}; const std::lock_guard current_stream_dump_lock{current_stream_dump_mutex};
if (current_stream_dump && current_stream_dump->output_) if (current_stream_dump && current_stream_dump->output_) {
dump_output = obs_output_get_ref(current_stream_dump->output_); dump_output = obs_output_get_ref(current_stream_dump->output_);
} }
if (dump_output) }
if (dump_output) {
obs_output_stop(dump_output); obs_output_stop(dump_output);
} }
}
static bool create_video_encoders(const GoLiveApi::Config &go_live_config, static bool create_video_encoders(const GoLiveApi::Config &go_live_config,
std::shared_ptr<obs_encoder_group_t> &video_encoder_group, obs_output_t *output, std::shared_ptr<obs_encoder_group_t> &video_encoder_group, obs_output_t *output,
@@ -589,8 +605,9 @@ static bool create_video_encoders(const GoLiveApi::Config &go_live_config,
} }
std::shared_ptr<obs_encoder_group_t> encoder_group(obs_encoder_group_create(), obs_encoder_group_destroy); std::shared_ptr<obs_encoder_group_t> encoder_group(obs_encoder_group_create(), obs_encoder_group_destroy);
if (!encoder_group) if (!encoder_group) {
return false; return false;
}
auto max_canvas_idx = canvases.size() - 1; auto max_canvas_idx = canvases.size() - 1;
@@ -603,15 +620,18 @@ static bool create_video_encoders(const GoLiveApi::Config &go_live_config,
auto &canvas = canvases[config.canvas_index]; auto &canvas = canvases[config.canvas_index];
auto encoder = create_video_encoder(video_encoder_name_buffer, i, config, canvas); auto encoder = create_video_encoder(video_encoder_name_buffer, i, config, canvas);
if (!encoder) if (!encoder) {
return false; return false;
}
if (!obs_encoder_set_group(encoder, encoder_group.get())) if (!obs_encoder_set_group(encoder, encoder_group.get())) {
return false; return false;
}
obs_output_set_video_encoder2(output, encoder, i); obs_output_set_video_encoder2(output, encoder, i);
if (recording_output) if (recording_output) {
obs_output_set_video_encoder2(recording_output, encoder, i); obs_output_set_video_encoder2(recording_output, encoder, i);
}
auto &data = go_live_config.encoder_configurations[i].bitrate_interpolation_points; auto &data = go_live_config.encoder_configurations[i].bitrate_interpolation_points;
if (data.has_value()) { if (data.has_value()) {
@@ -633,16 +653,18 @@ static void create_audio_encoders(const GoLiveApi::Config &go_live_config,
{ {
speaker_layout speakers = SPEAKERS_UNKNOWN; speaker_layout speakers = SPEAKERS_UNKNOWN;
obs_audio_info oai = {}; obs_audio_info oai = {};
if (obs_get_audio_info(&oai)) if (obs_get_audio_info(&oai)) {
speakers = oai.speakers; speakers = oai.speakers;
}
current_layout = speakers; current_layout = speakers;
auto sanitize_audio_channels = [&](obs_encoder_t *encoder, uint32_t channels) { auto sanitize_audio_channels = [&](obs_encoder_t *encoder, uint32_t channels) {
speaker_layout target_speakers = SPEAKERS_UNKNOWN; speaker_layout target_speakers = SPEAKERS_UNKNOWN;
for (size_t i = 0; i <= (size_t)SPEAKERS_7POINT1; i++) { for (size_t i = 0; i <= (size_t)SPEAKERS_7POINT1; i++) {
if (get_audio_channels((speaker_layout)i) != channels) if (get_audio_channels((speaker_layout)i) != channels) {
continue; continue;
}
target_speakers = (speaker_layout)i; target_speakers = (speaker_layout)i;
break; break;
@@ -656,12 +678,14 @@ static void create_audio_encoders(const GoLiveApi::Config &go_live_config,
return; return;
} }
if (speakers != SPEAKERS_UNKNOWN && if (speakers != SPEAKERS_UNKNOWN &&
(channels > get_audio_channels(speakers) || speakers == target_speakers)) (channels > get_audio_channels(speakers) || speakers == target_speakers)) {
return; return;
}
auto it = std::find(std::begin(speaker_layouts), std::end(speaker_layouts), target_speakers); auto it = std::find(std::begin(speaker_layouts), std::end(speaker_layouts), target_speakers);
if (it == std::end(speaker_layouts)) if (it == std::end(speaker_layouts)) {
speaker_layouts.push_back(target_speakers); speaker_layouts.push_back(target_speakers);
}
}; };
using encoder_configs_type = decltype(go_live_config.audio_configurations.live); using encoder_configs_type = decltype(go_live_config.audio_configurations.live);
@@ -692,8 +716,9 @@ static void create_audio_encoders(const GoLiveApi::Config &go_live_config,
sanitize_audio_channels(audio_encoder, configs[i].channels); sanitize_audio_channels(audio_encoder, configs[i].channels);
obs_output_set_audio_encoder(output, audio_encoder, output_encoder_index); obs_output_set_audio_encoder(output, audio_encoder, output_encoder_index);
if (recording_output) if (recording_output) {
obs_output_set_audio_encoder(recording_output, audio_encoder, output_encoder_index); obs_output_set_audio_encoder(recording_output, audio_encoder, output_encoder_index);
}
output_encoder_index += 1; output_encoder_index += 1;
audio_encoders.emplace_back(std::move(audio_encoder)); audio_encoders.emplace_back(std::move(audio_encoder));
} }
@@ -701,8 +726,9 @@ static void create_audio_encoders(const GoLiveApi::Config &go_live_config,
create_encoders("multitrack video live audio", go_live_config.audio_configurations.live, main_audio_mixer); create_encoders("multitrack video live audio", go_live_config.audio_configurations.live, main_audio_mixer);
if (!vod_track_mixer.has_value()) if (!vod_track_mixer.has_value()) {
return; return;
}
// we already check for empty inside of `create_encoders` // we already check for empty inside of `create_encoders`
encoder_configs_type empty = {}; encoder_configs_type empty = {};
@@ -738,8 +764,9 @@ static const char *speaker_layout_to_string(speaker_layout layout)
static void handle_speaker_layout_issues(QWidget *parent, const QString &multitrack_video_name, static void handle_speaker_layout_issues(QWidget *parent, const QString &multitrack_video_name,
const std::vector<speaker_layout> &requested_layouts, speaker_layout layout) const std::vector<speaker_layout> &requested_layouts, speaker_layout layout)
{ {
if (requested_layouts.empty()) if (requested_layouts.empty()) {
return; return;
}
QString message; QString message;
if (requested_layouts.size() == 1) { if (requested_layouts.size() == 1) {
@@ -783,13 +810,15 @@ static OBSOutputs SetupOBSOutput(QWidget *parent, const QString &multitrack_vide
{ {
auto output = create_output(); auto output = create_output();
OBSOutputAutoRelease recording_output; OBSOutputAutoRelease recording_output;
if (dump_stream_to_file_config) if (dump_stream_to_file_config) {
recording_output = create_recording_output(dump_stream_to_file_config); recording_output = create_recording_output(dump_stream_to_file_config);
}
json bitrate_interpolation_array = json::array(); json bitrate_interpolation_array = json::array();
if (!create_video_encoders(go_live_config, video_encoder_group, output, recording_output, if (!create_video_encoders(go_live_config, video_encoder_group, output, recording_output,
bitrate_interpolation_array, canvases)) bitrate_interpolation_array, canvases)) {
return {nullptr, nullptr}; return {nullptr, nullptr};
}
OBSDataAutoRelease settings = obs_output_get_settings(output); OBSDataAutoRelease settings = obs_output_get_settings(output);
// Only set interpolation_table_data if every encoder has interpolation points. Partial data would // Only set interpolation_table_data if every encoder has interpolation points. Partial data would
@@ -845,8 +874,9 @@ std::optional<MultitrackVideoOutput::OBSOutputObjects> MultitrackVideoOutput::ta
void MultitrackVideoOutput::ReleaseOnMainThread(std::optional<OBSOutputObjects> objects) void MultitrackVideoOutput::ReleaseOnMainThread(std::optional<OBSOutputObjects> objects)
{ {
if (!objects.has_value()) if (!objects.has_value()) {
return; return;
}
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
QApplication::instance()->thread(), [objects = std::move(objects)] {}, Qt::QueuedConnection); QApplication::instance()->thread(), [objects = std::move(objects)] {}, Qt::QueuedConnection);
@@ -866,11 +896,13 @@ void StreamStopHandler(void *arg, calldata_t *data)
OBSOutputAutoRelease stream_dump_output; OBSOutputAutoRelease stream_dump_output;
{ {
const std::lock_guard<std::mutex> current_stream_dump_lock{self->current_stream_dump_mutex}; const std::lock_guard<std::mutex> current_stream_dump_lock{self->current_stream_dump_mutex};
if (self->current_stream_dump && self->current_stream_dump->output_) if (self->current_stream_dump && self->current_stream_dump->output_) {
stream_dump_output = obs_output_get_ref(self->current_stream_dump->output_); stream_dump_output = obs_output_get_ref(self->current_stream_dump->output_);
} }
if (stream_dump_output) }
if (stream_dump_output) {
obs_output_stop(stream_dump_output); obs_output_stop(stream_dump_output);
}
/* Unregister the BPM (Broadcast Performance Metrics) callback and destroy the allocated metrics data. */ /* Unregister the BPM (Broadcast Performance Metrics) callback and destroy the allocated metrics data. */
obs_output_remove_packet_callback(static_cast<obs_output_t *>(calldata_ptr(data, "output")), bpm_inject, NULL); obs_output_remove_packet_callback(static_cast<obs_output_t *>(calldata_ptr(data, "output")), bpm_inject, NULL);
+10 -5
View File
@@ -30,8 +30,9 @@ Canvas::Canvas(Canvas &&other) noexcept
Canvas::~Canvas() noexcept Canvas::~Canvas() noexcept
{ {
if (!canvas) if (!canvas) {
return; return;
}
obs_canvas_remove(canvas); obs_canvas_remove(canvas);
obs_canvas_release(canvas); obs_canvas_release(canvas);
@@ -47,10 +48,12 @@ Canvas &Canvas::operator=(Canvas &&other) noexcept
std::optional<OBSDataAutoRelease> Canvas::Save() const std::optional<OBSDataAutoRelease> Canvas::Save() const
{ {
if (!canvas) if (!canvas) {
return std::nullopt; return std::nullopt;
if (obs_data_t *saved = obs_save_canvas(canvas)) }
if (obs_data_t *saved = obs_save_canvas(canvas)) {
return saved; return saved;
}
return std::nullopt; return std::nullopt;
} }
@@ -70,8 +73,9 @@ std::vector<Canvas> Canvas::LoadCanvases(obs_data_array_t *canvases)
{ {
auto cb = [](obs_data_t *data, void *param) -> void { auto cb = [](obs_data_t *data, void *param) -> void {
auto vec = static_cast<std::vector<Canvas> *>(param); auto vec = static_cast<std::vector<Canvas> *>(param);
if (auto canvas = Canvas::Load(data)) if (auto canvas = Canvas::Load(data)) {
vec->emplace_back(std::move(*canvas)); vec->emplace_back(std::move(*canvas));
}
}; };
std::vector<Canvas> ret; std::vector<Canvas> ret;
@@ -86,8 +90,9 @@ OBSDataArrayAutoRelease Canvas::SaveCanvases(const std::vector<Canvas> &canvases
for (auto &canvas : canvases) { for (auto &canvas : canvases) {
auto canvas_data = canvas.Save(); auto canvas_data = canvas.Save();
if (!canvas_data) if (!canvas_data) {
continue; continue;
}
OBSDataAutoRelease data = obs_data_create(); OBSDataAutoRelease data = obs_data_create();
obs_data_set_obj(data, "info", *canvas_data); obs_data_set_obj(data, "info", *canvas_data);
+6 -3
View File
@@ -4,11 +4,13 @@
int OBSProxyStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, int OBSProxyStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
QStyleHintReturn *returnData) const QStyleHintReturn *returnData) const
{ {
if (hint == SH_ComboBox_AllowWheelScrolling) if (hint == SH_ComboBox_AllowWheelScrolling) {
return 0; return 0;
}
#ifdef __APPLE__ #ifdef __APPLE__
if (hint == SH_ComboBox_UseNativePopup) if (hint == SH_ComboBox_UseNativePopup) {
return 1; return 1;
}
#endif #endif
return QProxyStyle::styleHint(hint, option, widget, returnData); return QProxyStyle::styleHint(hint, option, widget, returnData);
@@ -18,8 +20,9 @@ int OBSInvisibleCursorProxyStyle::pixelMetric(PixelMetric metric, const QStyleOp
const QWidget *widget) const const QWidget *widget) const
{ {
if (metric == PM_TextCursorWidth) if (metric == PM_TextCursorWidth) {
return 0; return 0;
}
return QProxyStyle::pixelMetric(metric, option, widget); return QProxyStyle::pixelMetric(metric, option, widget);
} }
+2 -1
View File
@@ -28,8 +28,9 @@ QString OBSTranslator::translate(const char *, const char *sourceText, const cha
const char *out = nullptr; const char *out = nullptr;
QString str(sourceText); QString str(sourceText);
str.replace(" ", ""); str.replace(" ", "");
if (!App()->TranslateString(QT_TO_UTF8(str), &out)) if (!App()->TranslateString(QT_TO_UTF8(str), &out)) {
return QString(sourceText); return QString(sourceText);
}
return QT_UTF8(out); return QT_UTF8(out);
} }
+5 -3
View File
@@ -25,13 +25,15 @@ static inline QString MakeQuickTransitionText(QuickTransition *qt)
{ {
QString name; QString name;
if (!qt->fadeToBlack) if (!qt->fadeToBlack) {
name = QT_UTF8(obs_source_get_name(qt->source)); name = QT_UTF8(obs_source_get_name(qt->source));
else } else {
name = QTStr("FadeToBlack"); name = QTStr("FadeToBlack");
}
if (!obs_transition_fixed(qt->source)) if (!obs_transition_fixed(qt->source)) {
name += QString(" (%1ms)").arg(QString::number(qt->duration)); name += QString(" (%1ms)").arg(QString::number(qt->duration));
}
return name; return name;
} }
+24 -12
View File
@@ -35,8 +35,9 @@ using Curl = unique_ptr<CURL, decltype(curl_deleter)>;
static size_t string_write(char *ptr, size_t size, size_t nmemb, string &str) static size_t string_write(char *ptr, size_t size, size_t nmemb, string &str)
{ {
size_t total = size * nmemb; size_t total = size * nmemb;
if (total) if (total) {
str.append(ptr, total); str.append(ptr, total);
}
return total; return total;
} }
@@ -66,8 +67,9 @@ void RemoteTextThread::run()
header = curl_slist_append(header, contentTypeString.c_str()); header = curl_slist_append(header, contentTypeString.c_str());
} }
for (std::string &h : extraHeaders) for (std::string &h : extraHeaders) {
header = curl_slist_append(header, h.c_str()); header = curl_slist_append(header, h.c_str());
}
curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()); curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, ""); curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, "");
@@ -78,8 +80,9 @@ void RemoteTextThread::run()
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str); curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str);
curl_obs_set_revoke_setting(curl.get()); curl_obs_set_revoke_setting(curl.get());
if (timeoutSec) if (timeoutSec) {
curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, timeoutSec); curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, timeoutSec);
}
if (!postData.empty()) { if (!postData.empty()) {
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, postData.c_str()); curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, postData.c_str());
@@ -103,13 +106,16 @@ static size_t header_write(char *ptr, size_t size, size_t nmemb, vector<string>
string str; string str;
size_t total = size * nmemb; size_t total = size * nmemb;
if (total) if (total) {
str.append(ptr, total); str.append(ptr, total);
}
if (str.back() == '\n') if (str.back() == '\n') {
str.resize(str.size() - 1); str.resize(str.size() - 1);
if (str.back() == '\r') }
if (str.back() == '\r') {
str.resize(str.size() - 1); str.resize(str.size() - 1);
}
list.push_back(std::move(str)); list.push_back(std::move(str));
return total; return total;
@@ -144,15 +150,17 @@ bool GetRemoteFile(const char *url, std::string &str, std::string &error, long *
header = curl_slist_append(header, contentTypeString.c_str()); header = curl_slist_append(header, contentTypeString.c_str());
} }
for (std::string &h : extraHeaders) for (std::string &h : extraHeaders) {
header = curl_slist_append(header, h.c_str()); header = curl_slist_append(header, h.c_str());
}
curl_easy_setopt(curl.get(), CURLOPT_URL, url); curl_easy_setopt(curl.get(), CURLOPT_URL, url);
curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, ""); curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, "");
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, header); curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, error_in); curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, error_in);
if (fail_on_error) if (fail_on_error) {
curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L); curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L);
}
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, string_write); curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, string_write);
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str); curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str);
curl_obs_set_revoke_setting(curl.get()); curl_obs_set_revoke_setting(curl.get());
@@ -162,20 +170,23 @@ bool GetRemoteFile(const char *url, std::string &str, std::string &error, long *
curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA, &header_in_list); curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA, &header_in_list);
} }
if (timeoutSec) if (timeoutSec) {
curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, timeoutSec); curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, timeoutSec);
}
if (!request_type.empty()) { if (!request_type.empty()) {
if (request_type != "GET") if (request_type != "GET") {
curl_easy_setopt(curl.get(), CURLOPT_CUSTOMREQUEST, request_type.c_str()); curl_easy_setopt(curl.get(), CURLOPT_CUSTOMREQUEST, request_type.c_str());
}
// Special case of "POST" // Special case of "POST"
if (request_type == "POST") { if (request_type == "POST") {
curl_easy_setopt(curl.get(), CURLOPT_POST, 1); curl_easy_setopt(curl.get(), CURLOPT_POST, 1);
if (!postData) if (!postData) {
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, "{}"); curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, "{}");
} }
} }
}
if (postData) { if (postData) {
if (postDataSize > 0) { if (postDataSize > 0) {
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDSIZE, (long)postDataSize); curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDSIZE, (long)postDataSize);
@@ -184,8 +195,9 @@ bool GetRemoteFile(const char *url, std::string &str, std::string &error, long *
} }
code = curl_easy_perform(curl.get()); code = curl_easy_perform(curl.get());
if (responseCode) if (responseCode) {
curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, responseCode); curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, responseCode);
}
if (code != CURLE_OK) { if (code != CURLE_OK) {
error = strlen(error_in) ? error_in : curl_easy_strerror(code); error = strlen(error_in) ? error_in : curl_easy_strerror(code);
@@ -125,10 +125,12 @@ void RemuxEntryPathItemDelegate::setModelData(QWidget *editor, QAbstractItemMode
if (pathListProp.isValid()) { if (pathListProp.isValid()) {
QStringList list = editor->property(PATH_LIST_PROP).toStringList(); QStringList list = editor->property(PATH_LIST_PROP).toStringList();
if (isOutput) { if (isOutput) {
if (list.size() > 0) if (list.size() > 0) {
model->setData(index, list); model->setData(index, list);
} else }
} else {
model->setData(index, list, RemuxEntryRole::NewPathsToProcessRole); model->setData(index, list, RemuxEntryRole::NewPathsToProcessRole);
}
} else { } else {
QLineEdit *lineEdit = editor->findChild<QLineEdit *>(); QLineEdit *lineEdit = editor->findChild<QLineEdit *>();
model->setData(index, lineEdit->text()); model->setData(index, lineEdit->text());
@@ -165,8 +167,9 @@ void RemuxEntryPathItemDelegate::handleBrowse(QWidget *container)
QLineEdit *text = container->findChild<QLineEdit *>(); QLineEdit *text = container->findChild<QLineEdit *>();
QString currentPath = text->text(); QString currentPath = text->text();
if (currentPath.isEmpty()) if (currentPath.isEmpty()) {
currentPath = defaultPath; currentPath = defaultPath;
}
bool isSet = false; bool isSet = false;
if (isOutput) { if (isOutput) {
@@ -190,9 +193,10 @@ void RemuxEntryPathItemDelegate::handleBrowse(QWidget *container)
#endif #endif
} }
if (isSet) if (isSet) {
emit commitData(container); emit commitData(container);
} }
}
void RemuxEntryPathItemDelegate::handleClear(QWidget *container) void RemuxEntryPathItemDelegate::handleClear(QWidget *container)
{ {
+16 -9
View File
@@ -218,10 +218,11 @@ void RemuxQueueModel::checkInputPath(int row)
} else { } else {
entry.sourcePath = QDir::toNativeSeparators(entry.sourcePath); entry.sourcePath = QDir::toNativeSeparators(entry.sourcePath);
QFileInfo fileInfo(entry.sourcePath); QFileInfo fileInfo(entry.sourcePath);
if (fileInfo.exists()) if (fileInfo.exists()) {
entry.state = RemuxEntryState::Ready; entry.state = RemuxEntryState::Ready;
else } else {
entry.state = RemuxEntryState::InvalidPath; entry.state = RemuxEntryState::InvalidPath;
}
QString newExt = ".mp4"; QString newExt = ".mp4";
QString suffix = fileInfo.suffix(); QString suffix = fileInfo.suffix();
@@ -230,13 +231,15 @@ void RemuxQueueModel::checkInputPath(int row)
newExt = ".remuxed." + suffix; newExt = ".remuxed." + suffix;
} }
if (entry.state == RemuxEntryState::Ready) if (entry.state == RemuxEntryState::Ready) {
entry.targetPath = QDir::toNativeSeparators(fileInfo.path() + QDir::separator() + entry.targetPath = QDir::toNativeSeparators(fileInfo.path() + QDir::separator() +
fileInfo.completeBaseName() + newExt); fileInfo.completeBaseName() + newExt);
} }
}
if (entry.state == RemuxEntryState::Ready && isProcessing) if (entry.state == RemuxEntryState::Ready && isProcessing) {
entry.state = RemuxEntryState::Pending; entry.state = RemuxEntryState::Pending;
}
emit dataChanged(index(row, 0), index(row, RemuxEntryColumn::Count)); emit dataChanged(index(row, 0), index(row, RemuxEntryColumn::Count));
} }
@@ -296,20 +299,23 @@ void RemuxQueueModel::clearFinished()
bool RemuxQueueModel::canClearFinished() const bool RemuxQueueModel::canClearFinished() const
{ {
bool canClearFinished = false; bool canClearFinished = false;
for (const RemuxQueueEntry &entry : queue) for (const RemuxQueueEntry &entry : queue) {
if (entry.state == RemuxEntryState::Complete) { if (entry.state == RemuxEntryState::Complete) {
canClearFinished = true; canClearFinished = true;
break; break;
} }
}
return canClearFinished; return canClearFinished;
} }
void RemuxQueueModel::beginProcessing() void RemuxQueueModel::beginProcessing()
{ {
for (RemuxQueueEntry &entry : queue) for (RemuxQueueEntry &entry : queue) {
if (entry.state == RemuxEntryState::Ready) if (entry.state == RemuxEntryState::Ready) {
entry.state = RemuxEntryState::Pending; entry.state = RemuxEntryState::Pending;
}
}
// Signal that the insertion point no longer exists. // Signal that the insertion point no longer exists.
beginRemoveRows(QModelIndex(), queue.length(), queue.length()); beginRemoveRows(QModelIndex(), queue.length(), queue.length());
@@ -366,10 +372,11 @@ void RemuxQueueModel::finishEntry(bool success)
for (int row = 0; row < queue.length(); row++) { for (int row = 0; row < queue.length(); row++) {
RemuxQueueEntry &entry = queue[row]; RemuxQueueEntry &entry = queue[row];
if (entry.state == RemuxEntryState::InProgress) { if (entry.state == RemuxEntryState::InProgress) {
if (success) if (success) {
entry.state = RemuxEntryState::Complete; entry.state = RemuxEntryState::Complete;
else } else {
entry.state = RemuxEntryState::Error; entry.state = RemuxEntryState::Error;
}
QModelIndex index = this->index(row, RemuxEntryColumn::State); QModelIndex index = this->index(row, RemuxEntryColumn::State);
emit dataChanged(index, index); emit dataChanged(index, index);

Some files were not shown because too many files have changed in this diff Show More