Add support for 3rd party service.xconfigs
3rd party service.xconfigs are located in %AppDataPath%/services (e.g. %APPDATA%/OBS/services in non-portable mode) and have the same format as a single service definition in services.xconfig without the id field, e.g.: "My Service" : { servers : { Primary : "rtmp://live.example.org/live" Secondary : "rtmp://live.example.com/live" } recommended : { "max bitrate" : 1337 } }master
parent
1ec1eb7e24
commit
edfbea5ba0
|
@ -301,6 +301,7 @@
|
|||
<ClCompile Include="Source\OBSVideoCapture.cpp" />
|
||||
<ClCompile Include="Source\RTMPPublisher.cpp" />
|
||||
<ClCompile Include="Source\RTMPStuff.cpp" />
|
||||
<ClCompile Include="Source\Service.cpp" />
|
||||
<ClCompile Include="Source\Settings.cpp" />
|
||||
<ClCompile Include="Source\SettingsAdvanced.cpp" />
|
||||
<ClCompile Include="Source\SettingsAudio.cpp" />
|
||||
|
|
|
@ -160,6 +160,9 @@
|
|||
<ClCompile Include="Source\SettingsQSV.cpp">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Source\Service.cpp">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Source\D3D10System.h">
|
||||
|
|
|
@ -588,6 +588,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
if(!OSFileExists(strUpdatePath) && !OSCreateDirectory(strUpdatePath))
|
||||
CrashError(TEXT("Couldn't create directory '%s'"), strUpdatePath.Array());
|
||||
|
||||
String servicesPath = strAppDataPath + L"\\services";
|
||||
if (!OSFileExists(servicesPath) && !OSCreateDirectory(servicesPath))
|
||||
CrashError(TEXT("Couldn't create directory '%s'"), servicesPath.Array());
|
||||
|
||||
LoadGlobalIni();
|
||||
|
||||
String strAllocator = GlobalConfig->GetString(TEXT("General"), TEXT("Allocator"));
|
||||
|
|
19
Source/OBS.h
19
Source/OBS.h
|
@ -16,6 +16,7 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
********************************************************************************/
|
||||
|
||||
#include <functional>
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -521,6 +522,24 @@ struct StreamInfo
|
|||
|
||||
//----------------------------
|
||||
|
||||
struct ServiceIdentifier
|
||||
{
|
||||
int id;
|
||||
String file;
|
||||
|
||||
ServiceIdentifier(int id, String file) : id(id), file(file) {}
|
||||
bool operator==(const ServiceIdentifier &sid) { return id == sid.id && file == sid.file; }
|
||||
bool operator!=(const ServiceIdentifier &sid) { return !(*this == sid); }
|
||||
};
|
||||
|
||||
std::vector<ServiceIdentifier> LoadServiceIdentifiers();
|
||||
void EnumerateServices(std::function<bool(ServiceIdentifier, XElement*)>);
|
||||
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(const ServiceIdentifier&, String *failReason=nullptr);
|
||||
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(String *failReason=nullptr);
|
||||
ServiceIdentifier GetCurrentService();
|
||||
|
||||
//----------------------------
|
||||
|
||||
struct StatusBarDrawData
|
||||
{
|
||||
UINT bytesPerSec;
|
||||
|
|
|
@ -830,7 +830,6 @@ DWORD WINAPI RTMPPublisher::CreateConnectionThread(RTMPPublisher *publisher)
|
|||
String failReason;
|
||||
String strBindIP;
|
||||
|
||||
int serviceID = AppConfig->GetInt (TEXT("Publish"), TEXT("Service"));
|
||||
String strURL = AppConfig->GetString(TEXT("Publish"), TEXT("URL"));
|
||||
String strPlayPath = AppConfig->GetString(TEXT("Publish"), TEXT("PlayPath"));
|
||||
|
||||
|
@ -851,6 +850,10 @@ DWORD WINAPI RTMPPublisher::CreateConnectionThread(RTMPPublisher *publisher)
|
|||
|
||||
//--------------------------------
|
||||
|
||||
ServiceIdentifier sid = GetCurrentService();
|
||||
|
||||
//--------------------------------
|
||||
|
||||
if(!strURL.IsValid())
|
||||
{
|
||||
failReason = TEXT("No server specified to connect to");
|
||||
|
@ -858,38 +861,15 @@ DWORD WINAPI RTMPPublisher::CreateConnectionThread(RTMPPublisher *publisher)
|
|||
}
|
||||
|
||||
// A service ID implies the settings have come from the xconfig file.
|
||||
if(serviceID != 0)
|
||||
if(sid.id != 0 || sid.file.IsValid())
|
||||
{
|
||||
XConfig serverData;
|
||||
if (!serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
{
|
||||
failReason = TEXT("Could not open services.xconfig");
|
||||
goto end;
|
||||
}
|
||||
|
||||
XElement *services = serverData.GetElement(TEXT("services"));
|
||||
if(!services)
|
||||
{
|
||||
failReason = TEXT("Could not find any services in services.xconfig");
|
||||
goto end;
|
||||
}
|
||||
|
||||
XElement *service = NULL;
|
||||
DWORD numServices = services->NumElements();
|
||||
for(UINT i=0; i<numServices; i++)
|
||||
{
|
||||
XElement *curService = services->GetElementByID(i);
|
||||
if(curService->GetInt(TEXT("id")) == serviceID)
|
||||
{
|
||||
// Found the service in the xconfig file.
|
||||
service = curService;
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto serviceData = LoadService(&failReason);
|
||||
auto service = serviceData.second;
|
||||
|
||||
if(!service)
|
||||
{
|
||||
failReason = TEXT("Could not find the service specified in services.xconfig");
|
||||
if (failReason.IsEmpty())
|
||||
failReason = TEXT("Could not find the service specified in services.xconfig");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/********************************************************************************
|
||||
Copyright (C) 2014 Ruwen Hahn <palana@stunned.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static inline void LoadBuiltinServices(vector<ServiceIdentifier> &services_)
|
||||
{
|
||||
XConfig serverData;
|
||||
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
{
|
||||
XElement *services = serverData.GetElement(TEXT("services"));
|
||||
if (services)
|
||||
{
|
||||
auto numServices = services->NumElements();
|
||||
|
||||
for (decltype(numServices) i = 0; i < numServices; i++)
|
||||
{
|
||||
auto service = services->GetElementByID(i);
|
||||
if (!service)
|
||||
continue;
|
||||
|
||||
services_.emplace_back(service->GetInt(L"id"), String());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void LoadUserServices(vector<ServiceIdentifier> &services)
|
||||
{
|
||||
OSFindData findData;
|
||||
String servicesDir = FormattedString(L"%s/services/", API->GetAppDataPath());
|
||||
if (HANDLE find = OSFindFirstFile(FormattedString(L"%s/*.xconfig", servicesDir.Array()), findData))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (findData.bDirectory)
|
||||
continue;
|
||||
|
||||
XConfig service(servicesDir + findData.fileName);
|
||||
if (!service.IsOpen())
|
||||
continue;
|
||||
|
||||
services.emplace_back(0, findData.fileName);
|
||||
} while (OSFindNextFile(find, findData));
|
||||
|
||||
OSFindClose(find);
|
||||
}
|
||||
}
|
||||
|
||||
vector<ServiceIdentifier> LoadServiceIdentifiers()
|
||||
{
|
||||
vector<ServiceIdentifier> services;
|
||||
|
||||
LoadBuiltinServices(services);
|
||||
LoadUserServices(services);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
static inline bool EnumerateBuiltinServices(function<bool(ServiceIdentifier, XElement*)> &func)
|
||||
{
|
||||
|
||||
XConfig serverData;
|
||||
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
{
|
||||
XElement *services = serverData.GetElement(TEXT("services"));
|
||||
if (services)
|
||||
{
|
||||
auto numServices = services->NumElements();
|
||||
|
||||
for (decltype(numServices) i = 0; i < numServices; i++)
|
||||
{
|
||||
auto service = services->GetElementByID(i);
|
||||
if (!service)
|
||||
continue;
|
||||
|
||||
if (!func({ service->GetInt(L"id"), String() }, service))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void EnumerateUserServices(function<bool(ServiceIdentifier, XElement*)> &func)
|
||||
{
|
||||
OSFindData findData;
|
||||
String servicesDir = FormattedString(L"%s/services/", API->GetAppDataPath());
|
||||
if (HANDLE find = OSFindFirstFile(FormattedString(L"%s/*.xconfig", servicesDir.Array()), findData))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (findData.bDirectory)
|
||||
continue;
|
||||
|
||||
XConfig service(servicesDir + findData.fileName);
|
||||
if (!service.IsOpen())
|
||||
continue;
|
||||
|
||||
func({ 0, findData.fileName }, service.GetElementByID(0));
|
||||
} while (OSFindNextFile(find, findData));
|
||||
|
||||
OSFindClose(find);
|
||||
}
|
||||
}
|
||||
|
||||
void EnumerateServices(function<bool(ServiceIdentifier, XElement*)> func)
|
||||
{
|
||||
if (!EnumerateBuiltinServices(func))
|
||||
return;
|
||||
|
||||
EnumerateUserServices(func);
|
||||
}
|
||||
|
||||
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(const ServiceIdentifier& sid, String *failReason)
|
||||
{
|
||||
auto fail = [&](CTSTR reason)
|
||||
{
|
||||
if (failReason)
|
||||
*failReason = reason;
|
||||
return make_pair(std::unique_ptr<XConfig>(), nullptr);
|
||||
};
|
||||
|
||||
auto serverData = make_unique<XConfig>();
|
||||
|
||||
if (sid.file.IsEmpty())
|
||||
{
|
||||
if (!serverData->Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
return fail(L"Could not open services.xconfig");
|
||||
|
||||
XElement *services = serverData->GetElement(TEXT("services"));
|
||||
if (!services)
|
||||
return fail(L"Could not find any services in services.xconfig");
|
||||
|
||||
XElement *service = NULL;
|
||||
auto numServices = services->NumElements();
|
||||
for (decltype(numServices) i = 0; i < numServices; i++)
|
||||
{
|
||||
XElement *curService = services->GetElementByID(i);
|
||||
if (!curService)
|
||||
continue;
|
||||
|
||||
if (curService->GetInt(L"id") == sid.id)
|
||||
return { move(serverData), curService };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (serverData->Open(FormattedString(L"%s/services/%s", API->GetAppDataPath(), sid.file.Array())))
|
||||
return { move(serverData), serverData->GetElementByID(sid.id) };
|
||||
else
|
||||
return fail(FormattedString(L"Could not open service file '%s'", sid.file.Array()));
|
||||
}
|
||||
|
||||
return make_pair(std::unique_ptr<XConfig>(), nullptr);
|
||||
}
|
||||
|
||||
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(String *failReason)
|
||||
{
|
||||
return LoadService(GetCurrentService(), failReason);
|
||||
}
|
||||
|
||||
ServiceIdentifier GetCurrentService()
|
||||
{
|
||||
int serviceID = AppConfig->GetInt(L"Publish", L"Service", 0);
|
||||
String serviceFile = AppConfig->GetString(L"Publish", L"ServiceFile");
|
||||
return { serviceID, serviceFile };
|
||||
}
|
|
@ -102,6 +102,7 @@ private:
|
|||
|
||||
//-----------------------------------------------------------------------
|
||||
// Private members
|
||||
std::vector<ServiceIdentifier> services;
|
||||
|
||||
private:
|
||||
void SetWarningInfo();
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
|
||||
#pragma warning(disable: 4530)
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
//============================================================================
|
||||
// Helpers
|
||||
|
@ -109,10 +112,11 @@ void SettingsPublish::ApplySettings()
|
|||
AppConfig->SetInt(TEXT("Publish"), TEXT("Mode"), curSel);
|
||||
|
||||
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0);
|
||||
if(serviceID != CB_ERR)
|
||||
if(serviceID != CB_ERR && serviceID >= 0 && serviceID < (int)services.size())
|
||||
{
|
||||
serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, serviceID, 0);
|
||||
AppConfig->SetInt(TEXT("Publish"), TEXT("Service"), serviceID);
|
||||
auto sid = services[serviceID];
|
||||
AppConfig->SetInt(TEXT("Publish"), TEXT("Service"), sid.id);
|
||||
AppConfig->SetString(L"Publish", L"ServiceFile", sid.file);
|
||||
}
|
||||
|
||||
String strTemp = GetEditText(GetDlgItem(hwnd, IDC_PLAYPATH));
|
||||
|
@ -198,7 +202,7 @@ bool SettingsPublish::HasDefaults() const
|
|||
|
||||
void SettingsPublish::SetWarningInfo()
|
||||
{
|
||||
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0);
|
||||
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0);
|
||||
|
||||
bool bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0;
|
||||
int maxBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000);
|
||||
|
@ -219,135 +223,127 @@ void SettingsPublish::SetWarningInfo()
|
|||
bool canOptimize = false;
|
||||
String strWarnings;
|
||||
|
||||
XConfig serverData;
|
||||
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
if (serviceID >= 0 && serviceID < (int)services.size())
|
||||
{
|
||||
XElement *services = serverData.GetElement(TEXT("services"));
|
||||
if(services)
|
||||
auto serviceData = LoadService(services[serviceID]);
|
||||
auto service = serviceData.second;
|
||||
if (service)
|
||||
{
|
||||
UINT numServices = services->NumElements();
|
||||
|
||||
for(UINT i=0; i<numServices; i++)
|
||||
if (service->GetInt(TEXT("id")) == serviceID)
|
||||
{
|
||||
XElement *service = services->GetElementByID(i);
|
||||
if (service->GetInt(TEXT("id")) == serviceID)
|
||||
strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName());
|
||||
|
||||
//check to see if the service we're using has recommendations
|
||||
if (!service->HasItem(TEXT("recommended")))
|
||||
{
|
||||
strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName());
|
||||
SetDlgItemText(hwnd, IDC_WARNINGS, TEXT(""));
|
||||
return;
|
||||
}
|
||||
|
||||
//check to see if the service we're using has recommendations
|
||||
if (!service->HasItem(TEXT("recommended")))
|
||||
XElement *r = service->GetElement(TEXT("recommended"));
|
||||
|
||||
if (r->HasItem(TEXT("ratecontrol")))
|
||||
{
|
||||
CTSTR rc = r->GetString(TEXT("ratecontrol"));
|
||||
if (!scmp(rc, TEXT("cbr")) && !bUseCBR)
|
||||
{
|
||||
SetDlgItemText(hwnd, IDC_WARNINGS, TEXT(""));
|
||||
return;
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << Str("Settings.Publish.Warning.UseCBR");
|
||||
}
|
||||
}
|
||||
|
||||
XElement *r = service->GetElement(TEXT("recommended"));
|
||||
|
||||
if (r->HasItem(TEXT("ratecontrol")))
|
||||
if (r->HasItem(TEXT("max bitrate")))
|
||||
{
|
||||
int max_bitrate = r->GetInt(TEXT("max bitrate"));
|
||||
if (maxBitRate > max_bitrate)
|
||||
{
|
||||
CTSTR rc = r->GetString(TEXT("ratecontrol"));
|
||||
if (!scmp (rc, TEXT("cbr")) && !bUseCBR)
|
||||
{
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << Str("Settings.Publish.Warning.UseCBR");
|
||||
}
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate);
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(TEXT("max bitrate")))
|
||||
if (r->HasItem(L"supported audio codec"))
|
||||
{
|
||||
StringList codecs;
|
||||
r->GetStringList(L"supported audio codec", codecs);
|
||||
if (codecs.FindValueIndex(currentAudioCodec) == INVALID)
|
||||
{
|
||||
int max_bitrate = r->GetInt(TEXT("max bitrate"));
|
||||
if (maxBitRate > max_bitrate)
|
||||
{
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate);
|
||||
}
|
||||
String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution
|
||||
msg.FindReplace(L"$1", codecs[0].Array());
|
||||
msg.FindReplace(L"$2", currentAudioCodec.Array());
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << msg;
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(L"supported audio codec"))
|
||||
if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC"))))
|
||||
{
|
||||
int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac"));
|
||||
if (audioBitRate > maxaudioaac)
|
||||
{
|
||||
StringList codecs;
|
||||
r->GetStringList(L"supported audio codec", codecs);
|
||||
if (codecs.FindValueIndex(currentAudioCodec) == INVALID)
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac);
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3"))))
|
||||
{
|
||||
int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3"));
|
||||
if (audioBitRate > maxaudiomp3)
|
||||
{
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3);
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(L"video aspect ratio"))
|
||||
{
|
||||
String aspectRatio = r->GetString(L"video aspect ratio");
|
||||
StringList numbers;
|
||||
aspectRatio.GetTokenList(numbers, ':');
|
||||
if (numbers.Num() == 2)
|
||||
{
|
||||
float aspect = numbers[0].ToInt() / max(1.f, numbers[1].ToFloat());
|
||||
if (!CloseFloat(aspect, currentAspect))
|
||||
{
|
||||
String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution
|
||||
msg.FindReplace(L"$1", codecs[0].Array());
|
||||
msg.FindReplace(L"$2", currentAudioCodec.Array());
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
String aspectLocalized = Str("Settings.Video.AspectRatioFormat");
|
||||
aspectLocalized.FindReplace(L"$1", UIntString(numbers[0].ToInt()));
|
||||
aspectLocalized.FindReplace(L"$2", UIntString(numbers[1].ToInt()));
|
||||
|
||||
String msg = Str("Settings.Publish.Warning.VideoAspectRatio");
|
||||
msg.FindReplace(L"$1", aspectLocalized);
|
||||
strWarnings << msg;
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC"))))
|
||||
{
|
||||
int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac"));
|
||||
if (audioBitRate > maxaudioaac)
|
||||
{
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3"))))
|
||||
if (r->HasItem(TEXT("profile")))
|
||||
{
|
||||
String expectedProfile = r->GetString(TEXT("profile"));
|
||||
|
||||
if (!expectedProfile.CompareI(currentx264Profile))
|
||||
{
|
||||
int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3"));
|
||||
if (audioBitRate > maxaudiomp3)
|
||||
{
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3);
|
||||
}
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile");
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(L"video aspect ratio"))
|
||||
if (r->HasItem(TEXT("keyint")))
|
||||
{
|
||||
int keyint = r->GetInt(TEXT("keyint"));
|
||||
if (!keyframeInt || keyframeInt * 1000 > keyint)
|
||||
{
|
||||
String aspectRatio = r->GetString(L"video aspect ratio");
|
||||
StringList numbers;
|
||||
aspectRatio.GetTokenList(numbers, ':');
|
||||
if (numbers.Num() == 2)
|
||||
{
|
||||
float aspect = numbers[0].ToInt() / max(1.f, numbers[1].ToFloat());
|
||||
if (!CloseFloat(aspect, currentAspect))
|
||||
{
|
||||
String aspectLocalized = Str("Settings.Video.AspectRatioFormat");
|
||||
aspectLocalized.FindReplace(L"$1", UIntString(numbers[0].ToInt()));
|
||||
aspectLocalized.FindReplace(L"$2", UIntString(numbers[1].ToInt()));
|
||||
|
||||
String msg = Str("Settings.Publish.Warning.VideoAspectRatio");
|
||||
msg.FindReplace(L"$1", aspectLocalized);
|
||||
strWarnings << msg;
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000);
|
||||
}
|
||||
|
||||
if (r->HasItem(TEXT("profile")))
|
||||
{
|
||||
String expectedProfile = r->GetString(TEXT("profile"));
|
||||
|
||||
if (!expectedProfile.CompareI(currentx264Profile))
|
||||
{
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile");
|
||||
}
|
||||
}
|
||||
|
||||
if (r->HasItem(TEXT("keyint")))
|
||||
{
|
||||
int keyint = r->GetInt(TEXT("keyint"));
|
||||
if (!keyframeInt || keyframeInt * 1000 > keyint)
|
||||
{
|
||||
hasErrors = true;
|
||||
canOptimize = true;
|
||||
strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,32 +386,21 @@ static void UpdateMemoryUsage(HWND hwnd)
|
|||
void SettingsPublish::OptimizeSettings()
|
||||
{
|
||||
auto refresh_on_exit = GuardScope([&] { SetWarningInfo(); UpdateMemoryUsage(hwnd); });
|
||||
XConfig serverData;
|
||||
if (!serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
|
||||
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0);
|
||||
if (serviceID < 0 || serviceID >= (int)services.size())
|
||||
return;
|
||||
|
||||
XElement *services = serverData.GetElement(L"services");
|
||||
if (!services)
|
||||
auto serviceData = LoadService(services[serviceID]);
|
||||
auto service = serviceData.second;
|
||||
if (!service)
|
||||
return;
|
||||
|
||||
//check to see if the service we're using has recommendations
|
||||
if (!service->HasItem(L"recommended"))
|
||||
return;
|
||||
|
||||
UINT numServices = services->NumElements();
|
||||
|
||||
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0);
|
||||
XElement *r = nullptr;
|
||||
for (UINT i = 0; i < numServices; i++)
|
||||
{
|
||||
XElement *service = services->GetElementByID(i);
|
||||
if (service->GetInt(L"id") != serviceID)
|
||||
continue;
|
||||
|
||||
//check to see if the service we're using has recommendations
|
||||
if (!service->HasItem(L"recommended"))
|
||||
return;
|
||||
|
||||
r = service->GetElement(L"recommended");
|
||||
break;
|
||||
}
|
||||
|
||||
XElement *r = service->GetElement(L"recommended");
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
|
@ -544,27 +529,53 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
|||
hwndTemp = GetDlgItem(hwnd, IDC_SERVICE);
|
||||
int itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("Custom"));
|
||||
SendMessage(hwndTemp, CB_SETITEMDATA, itemId, 0);
|
||||
services.emplace_back(0, String());
|
||||
|
||||
UINT numServices = 0;
|
||||
|
||||
XConfig serverData;
|
||||
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
ServiceIdentifier current = GetCurrentService();
|
||||
std::unordered_map<std::wstring, int> duplicates;
|
||||
|
||||
EnumerateServices([&](ServiceIdentifier sid, XElement *service)
|
||||
{
|
||||
XElement *services = serverData.GetElement(TEXT("services"));
|
||||
if(services)
|
||||
services.emplace_back(sid);
|
||||
auto pos = duplicates.find(service->GetName());
|
||||
int id;
|
||||
if (pos != end(duplicates))
|
||||
{
|
||||
numServices = services->NumElements();
|
||||
|
||||
for(UINT i=0; i<numServices; i++)
|
||||
const ServiceIdentifier &first = services[pos->second];
|
||||
if (first.file.IsValid())
|
||||
{
|
||||
XElement *service = services->GetElementByID(i);
|
||||
itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)service->GetName());
|
||||
SendMessage(hwndTemp, CB_SETITEMDATA, itemId, service->GetInt(TEXT("id")));
|
||||
SendMessage(hwndTemp, CB_DELETESTRING, pos->second, 0);
|
||||
SendMessage(hwndTemp, CB_INSERTSTRING, pos->second, (LPARAM)FormattedString(L"%s [%s]", service->GetName(), services[pos->second].file.Array()).Array());
|
||||
}
|
||||
id = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)(sid.file.IsValid() ? FormattedString(L"%s [%s]", service->GetName(), sid.file.Array()).Array() : service->GetName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
id = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)service->GetName());
|
||||
duplicates[service->GetName()] = id;
|
||||
}
|
||||
}
|
||||
|
||||
int serviceID = AppConfig->GetInt(TEXT("Publish"), TEXT("Service"), 0);
|
||||
[&]()
|
||||
{
|
||||
if (sid != current)
|
||||
return;
|
||||
|
||||
SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, id, 0);
|
||||
|
||||
XElement *servers = service->GetElement(L"servers");
|
||||
if (!servers)
|
||||
return;
|
||||
|
||||
UINT numServers = servers->NumDataItems();
|
||||
for (UINT i = 0; i < numServers; i++)
|
||||
{
|
||||
XDataItem *server = servers->GetDataItemByID(i);
|
||||
SendMessage(GetDlgItem(hwnd, IDC_SERVERLIST), CB_ADDSTRING, 0, (LPARAM)server->GetName());
|
||||
}
|
||||
|
||||
}();
|
||||
return true;
|
||||
});
|
||||
|
||||
if(mode != 0) ShowWindow(hwndTemp, SW_HIDE);
|
||||
|
||||
|
@ -574,7 +585,7 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
|||
LoadSettingEditString(hwndTemp, TEXT("Publish"), TEXT("PlayPath"), NULL);
|
||||
if(mode != 0) ShowWindow(hwndTemp, SW_HIDE);
|
||||
|
||||
if(serviceID == 0) //custom
|
||||
if(current.file.IsEmpty() && current.id == 0) //custom
|
||||
{
|
||||
ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE);
|
||||
hwndTemp = GetDlgItem(hwnd, IDC_URL);
|
||||
|
@ -585,38 +596,6 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
|||
{
|
||||
ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE);
|
||||
hwndTemp = GetDlgItem(hwnd, IDC_SERVERLIST);
|
||||
|
||||
XElement *services = serverData.GetElement(TEXT("services"));
|
||||
if(services)
|
||||
{
|
||||
XElement *service = NULL;
|
||||
numServices = services->NumElements();
|
||||
for(UINT i=0; i<numServices; i++)
|
||||
{
|
||||
XElement *curService = services->GetElementByID(i);
|
||||
if(curService->GetInt(TEXT("id")) == serviceID)
|
||||
{
|
||||
SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, i+1, 0);
|
||||
service = curService;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(service)
|
||||
{
|
||||
XElement *servers = service->GetElement(TEXT("servers"));
|
||||
if(servers)
|
||||
{
|
||||
UINT numServers = servers->NumDataItems();
|
||||
for(UINT i=0; i<numServers; i++)
|
||||
{
|
||||
XDataItem *server = servers->GetDataItemByID(i);
|
||||
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoadSettingComboString(hwndTemp, TEXT("Publish"), TEXT("URL"), NULL);
|
||||
}
|
||||
|
||||
|
@ -937,24 +916,20 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
|||
ShowWindow(hwndTemp, SW_SHOW);
|
||||
SendMessage(hwndTemp, CB_RESETCONTENT, 0, 0);
|
||||
|
||||
XConfig serverData;
|
||||
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
|
||||
if (serviceID >= 0 && serviceID < (int)services.size())
|
||||
{
|
||||
XElement *services = serverData.GetElement(TEXT("services"));
|
||||
if(services)
|
||||
auto serviceData = LoadService(services[serviceID]);
|
||||
auto service = serviceData.second;
|
||||
if (service)
|
||||
{
|
||||
XElement *service = services->GetElementByID(serviceID-1);
|
||||
if(service)
|
||||
XElement *servers = service->GetElement(TEXT("servers"));
|
||||
if (servers)
|
||||
{
|
||||
XElement *servers = service->GetElement(TEXT("servers"));
|
||||
if(servers)
|
||||
UINT numServers = servers->NumDataItems();
|
||||
for (UINT i = 0; i < numServers; i++)
|
||||
{
|
||||
UINT numServers = servers->NumDataItems();
|
||||
for(UINT i=0; i<numServers; i++)
|
||||
{
|
||||
XDataItem *server = servers->GetDataItemByID(i);
|
||||
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName());
|
||||
}
|
||||
XDataItem *server = servers->GetDataItemByID(i);
|
||||
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue