1
0

window-basic-settings.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409
  1. /******************************************************************************
  2. Copyright (C) 2013-2014 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include <obs.hpp>
  15. #include <util/util.hpp>
  16. #include <util/lexer.h>
  17. #include <sstream>
  18. #include <QLineEdit>
  19. #include <QMessageBox>
  20. #include <QCloseEvent>
  21. #include <QFileDialog>
  22. #include "obs-app.hpp"
  23. #include "platform.hpp"
  24. #include "properties-view.hpp"
  25. #include "qt-wrappers.hpp"
  26. #include "window-basic-main.hpp"
  27. #include "window-basic-settings.hpp"
  28. #include <util/platform.h>
  29. using namespace std;
  30. /* parses "[width]x[height]", string, i.e. 1024x768 */
  31. static bool ConvertResText(const char *res, uint32_t &cx, uint32_t &cy)
  32. {
  33. BaseLexer lex;
  34. base_token token;
  35. lexer_start(lex, res);
  36. /* parse width */
  37. if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  38. return false;
  39. if (token.type != BASETOKEN_DIGIT)
  40. return false;
  41. cx = std::stoul(token.text.array);
  42. /* parse 'x' */
  43. if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  44. return false;
  45. if (strref_cmpi(&token.text, "x") != 0)
  46. return false;
  47. /* parse height */
  48. if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  49. return false;
  50. if (token.type != BASETOKEN_DIGIT)
  51. return false;
  52. cy = std::stoul(token.text.array);
  53. /* shouldn't be any more tokens after this */
  54. if (lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  55. return false;
  56. return true;
  57. }
  58. static inline bool WidgetChanged(QWidget *widget)
  59. {
  60. return widget->property("changed").toBool();
  61. }
  62. static inline void SetComboByName(QComboBox *combo, const char *name)
  63. {
  64. int idx = combo->findText(QT_UTF8(name));
  65. if (idx != -1)
  66. combo->setCurrentIndex(idx);
  67. }
  68. static inline void SetComboByValue(QComboBox *combo, const char *name)
  69. {
  70. int idx = combo->findData(QT_UTF8(name));
  71. if (idx != -1)
  72. combo->setCurrentIndex(idx);
  73. }
  74. static inline QString GetComboData(QComboBox *combo)
  75. {
  76. int idx = combo->currentIndex();
  77. if (idx == -1)
  78. return QString();
  79. return combo->itemData(idx).toString();
  80. }
  81. void OBSBasicSettings::HookWidget(QWidget *widget, const char *signal,
  82. const char *slot)
  83. {
  84. QObject::connect(widget, signal, this, slot);
  85. widget->setProperty("changed", QVariant(false));
  86. }
  87. #define COMBO_CHANGED SIGNAL(currentIndexChanged(int))
  88. #define EDIT_CHANGED SIGNAL(textChanged(const QString &))
  89. #define CBEDIT_CHANGED SIGNAL(editTextChanged(const QString &))
  90. #define CHECK_CHANGED SIGNAL(clicked(bool))
  91. #define SCROLL_CHANGED SIGNAL(valueChanged(int))
  92. #define GENERAL_CHANGED SLOT(GeneralChanged())
  93. #define STREAM1_CHANGED SLOT(Stream1Changed())
  94. #define OUTPUTS_CHANGED SLOT(OutputsChanged())
  95. #define AUDIO_RESTART SLOT(AudioChangedRestart())
  96. #define AUDIO_CHANGED SLOT(AudioChanged())
  97. #define VIDEO_RESTART SLOT(VideoChangedRestart())
  98. #define VIDEO_RES SLOT(VideoChangedResolution())
  99. #define VIDEO_CHANGED SLOT(VideoChanged())
  100. OBSBasicSettings::OBSBasicSettings(QWidget *parent)
  101. : QDialog (parent),
  102. main (qobject_cast<OBSBasic*>(parent)),
  103. ui (new Ui::OBSBasicSettings)
  104. {
  105. string path;
  106. ui->setupUi(this);
  107. HookWidget(ui->language, COMBO_CHANGED, GENERAL_CHANGED);
  108. HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED);
  109. HookWidget(ui->streamType, COMBO_CHANGED, STREAM1_CHANGED);
  110. HookWidget(ui->simpleOutputPath, EDIT_CHANGED, OUTPUTS_CHANGED);
  111. HookWidget(ui->simpleOutputVBitrate, SCROLL_CHANGED, OUTPUTS_CHANGED);
  112. HookWidget(ui->simpleOutputABitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
  113. HookWidget(ui->simpleOutReconnect, CHECK_CHANGED, OUTPUTS_CHANGED);
  114. HookWidget(ui->simpleOutRetryDelay, SCROLL_CHANGED, OUTPUTS_CHANGED);
  115. HookWidget(ui->simpleOutMaxRetries, SCROLL_CHANGED, OUTPUTS_CHANGED);
  116. HookWidget(ui->simpleOutAdvanced, CHECK_CHANGED, OUTPUTS_CHANGED);
  117. HookWidget(ui->simpleOutUseCBR, CHECK_CHANGED, OUTPUTS_CHANGED);
  118. HookWidget(ui->simpleOutPreset, COMBO_CHANGED, OUTPUTS_CHANGED);
  119. HookWidget(ui->simpleOutUseBufsize, CHECK_CHANGED, OUTPUTS_CHANGED);
  120. HookWidget(ui->simpleOutPreset, COMBO_CHANGED, OUTPUTS_CHANGED);
  121. HookWidget(ui->simpleOutVBufsize, SCROLL_CHANGED, OUTPUTS_CHANGED);
  122. HookWidget(ui->advOutReconnect, CHECK_CHANGED, OUTPUTS_CHANGED);
  123. HookWidget(ui->advOutRetryDelay, SCROLL_CHANGED, OUTPUTS_CHANGED);
  124. HookWidget(ui->advOutMaxRetries, SCROLL_CHANGED, OUTPUTS_CHANGED);
  125. HookWidget(ui->advOutEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
  126. HookWidget(ui->advOutUseRescale, CHECK_CHANGED, OUTPUTS_CHANGED);
  127. HookWidget(ui->advOutRescale, CBEDIT_CHANGED, OUTPUTS_CHANGED);
  128. HookWidget(ui->advOutTrack1, CHECK_CHANGED, OUTPUTS_CHANGED);
  129. HookWidget(ui->advOutTrack2, CHECK_CHANGED, OUTPUTS_CHANGED);
  130. HookWidget(ui->advOutTrack3, CHECK_CHANGED, OUTPUTS_CHANGED);
  131. HookWidget(ui->advOutTrack4, CHECK_CHANGED, OUTPUTS_CHANGED);
  132. HookWidget(ui->advOutRecType, COMBO_CHANGED, OUTPUTS_CHANGED);
  133. HookWidget(ui->advOutRecPath, EDIT_CHANGED, OUTPUTS_CHANGED);
  134. HookWidget(ui->advOutRecEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
  135. HookWidget(ui->advOutRecUseRescale, CHECK_CHANGED, OUTPUTS_CHANGED);
  136. HookWidget(ui->advOutRecRescale, CBEDIT_CHANGED, OUTPUTS_CHANGED);
  137. HookWidget(ui->advOutRecTrack1, CHECK_CHANGED, OUTPUTS_CHANGED);
  138. HookWidget(ui->advOutRecTrack2, CHECK_CHANGED, OUTPUTS_CHANGED);
  139. HookWidget(ui->advOutRecTrack3, CHECK_CHANGED, OUTPUTS_CHANGED);
  140. HookWidget(ui->advOutRecTrack4, CHECK_CHANGED, OUTPUTS_CHANGED);
  141. HookWidget(ui->advOutFFURL, EDIT_CHANGED, OUTPUTS_CHANGED);
  142. HookWidget(ui->advOutFFVBitrate, SCROLL_CHANGED, OUTPUTS_CHANGED);
  143. HookWidget(ui->advOutFFUseRescale, CHECK_CHANGED, OUTPUTS_CHANGED);
  144. HookWidget(ui->advOutFFRescale, CBEDIT_CHANGED, OUTPUTS_CHANGED);
  145. HookWidget(ui->advOutFFVEncoder, EDIT_CHANGED, OUTPUTS_CHANGED);
  146. HookWidget(ui->advOutFFVCfg, EDIT_CHANGED, OUTPUTS_CHANGED);
  147. HookWidget(ui->advOutFFABitrate, SCROLL_CHANGED, OUTPUTS_CHANGED);
  148. HookWidget(ui->advOutFFTrack1, CHECK_CHANGED, OUTPUTS_CHANGED);
  149. HookWidget(ui->advOutFFTrack2, CHECK_CHANGED, OUTPUTS_CHANGED);
  150. HookWidget(ui->advOutFFTrack3, CHECK_CHANGED, OUTPUTS_CHANGED);
  151. HookWidget(ui->advOutFFTrack4, CHECK_CHANGED, OUTPUTS_CHANGED);
  152. HookWidget(ui->advOutFFAEncoder, EDIT_CHANGED, OUTPUTS_CHANGED);
  153. HookWidget(ui->advOutFFACfg, EDIT_CHANGED, OUTPUTS_CHANGED);
  154. HookWidget(ui->advOutTrack1Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
  155. HookWidget(ui->advOutTrack1Name, EDIT_CHANGED, OUTPUTS_CHANGED);
  156. HookWidget(ui->advOutTrack2Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
  157. HookWidget(ui->advOutTrack2Name, EDIT_CHANGED, OUTPUTS_CHANGED);
  158. HookWidget(ui->advOutTrack3Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
  159. HookWidget(ui->advOutTrack3Name, EDIT_CHANGED, OUTPUTS_CHANGED);
  160. HookWidget(ui->advOutTrack4Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
  161. HookWidget(ui->advOutTrack4Name, EDIT_CHANGED, OUTPUTS_CHANGED);
  162. HookWidget(ui->channelSetup, COMBO_CHANGED, AUDIO_RESTART);
  163. HookWidget(ui->sampleRate, COMBO_CHANGED, AUDIO_RESTART);
  164. HookWidget(ui->desktopAudioDevice1, COMBO_CHANGED, AUDIO_CHANGED);
  165. HookWidget(ui->desktopAudioDevice2, COMBO_CHANGED, AUDIO_CHANGED);
  166. HookWidget(ui->auxAudioDevice1, COMBO_CHANGED, AUDIO_CHANGED);
  167. HookWidget(ui->auxAudioDevice2, COMBO_CHANGED, AUDIO_CHANGED);
  168. HookWidget(ui->auxAudioDevice3, COMBO_CHANGED, AUDIO_CHANGED);
  169. HookWidget(ui->renderer, COMBO_CHANGED, VIDEO_RESTART);
  170. HookWidget(ui->adapter, COMBO_CHANGED, VIDEO_RESTART);
  171. HookWidget(ui->baseResolution, CBEDIT_CHANGED, VIDEO_RES);
  172. HookWidget(ui->outputResolution, CBEDIT_CHANGED, VIDEO_RES);
  173. HookWidget(ui->downscaleFilter, COMBO_CHANGED, VIDEO_CHANGED);
  174. HookWidget(ui->fpsType, COMBO_CHANGED, VIDEO_CHANGED);
  175. HookWidget(ui->fpsCommon, COMBO_CHANGED, VIDEO_CHANGED);
  176. HookWidget(ui->fpsInteger, SCROLL_CHANGED, VIDEO_CHANGED);
  177. HookWidget(ui->fpsInteger, SCROLL_CHANGED, VIDEO_CHANGED);
  178. HookWidget(ui->fpsNumerator, SCROLL_CHANGED, VIDEO_CHANGED);
  179. HookWidget(ui->fpsDenominator, SCROLL_CHANGED, VIDEO_CHANGED);
  180. //Apply button disabled until change.
  181. EnableApplyButton(false);
  182. LoadServiceTypes();
  183. LoadEncoderTypes();
  184. LoadSettings(false);
  185. }
  186. void OBSBasicSettings::SaveCombo(QComboBox *widget, const char *section,
  187. const char *value)
  188. {
  189. if (WidgetChanged(widget))
  190. config_set_string(main->Config(), section, value,
  191. QT_TO_UTF8(widget->currentText()));
  192. }
  193. void OBSBasicSettings::SaveComboData(QComboBox *widget, const char *section,
  194. const char *value)
  195. {
  196. if (WidgetChanged(widget)) {
  197. QString str = GetComboData(widget);
  198. config_set_string(main->Config(), section, value,
  199. QT_TO_UTF8(str));
  200. }
  201. }
  202. void OBSBasicSettings::SaveCheckBox(QAbstractButton *widget,
  203. const char *section, const char *value, bool invert)
  204. {
  205. if (WidgetChanged(widget)) {
  206. bool checked = widget->isChecked();
  207. if (invert) checked = !checked;
  208. config_set_bool(main->Config(), section, value, checked);
  209. }
  210. }
  211. void OBSBasicSettings::SaveEdit(QLineEdit *widget, const char *section,
  212. const char *value)
  213. {
  214. if (WidgetChanged(widget))
  215. config_set_string(main->Config(), section, value,
  216. QT_TO_UTF8(widget->text()));
  217. }
  218. void OBSBasicSettings::SaveSpinBox(QSpinBox *widget, const char *section,
  219. const char *value)
  220. {
  221. if (WidgetChanged(widget))
  222. config_set_int(main->Config(), section, value, widget->value());
  223. }
  224. void OBSBasicSettings::LoadServiceTypes()
  225. {
  226. const char *type;
  227. size_t idx = 0;
  228. while (obs_enum_service_types(idx++, &type)) {
  229. const char *name = obs_service_get_display_name(type);
  230. QString qName = QT_UTF8(name);
  231. QString qType = QT_UTF8(type);
  232. ui->streamType->addItem(qName, qType);
  233. }
  234. type = obs_service_get_type(main->GetService());
  235. SetComboByValue(ui->streamType, type);
  236. }
  237. #define TEXT_USE_STREAM_ENC \
  238. QTStr("Basic.Settings.Output.Adv.Recording.UseStreamEncoder")
  239. void OBSBasicSettings::LoadEncoderTypes()
  240. {
  241. const char *type;
  242. size_t idx = 0;
  243. ui->advOutRecEncoder->addItem(TEXT_USE_STREAM_ENC, "none");
  244. while (obs_enum_encoder_types(idx++, &type)) {
  245. const char *name = obs_encoder_get_display_name(type);
  246. const char *codec = obs_get_encoder_codec(type);
  247. if (strcmp(codec, "h264") != 0)
  248. continue;
  249. QString qName = QT_UTF8(name);
  250. QString qType = QT_UTF8(type);
  251. ui->advOutEncoder->addItem(qName, qType);
  252. ui->advOutRecEncoder->addItem(qName, qType);
  253. }
  254. }
  255. void OBSBasicSettings::LoadLanguageList()
  256. {
  257. const char *currentLang = App()->GetLocale();
  258. ui->language->clear();
  259. for (const auto &locale : GetLocaleNames()) {
  260. int idx = ui->language->count();
  261. ui->language->addItem(QT_UTF8(locale.second.c_str()),
  262. QT_UTF8(locale.first.c_str()));
  263. if (locale.first == currentLang)
  264. ui->language->setCurrentIndex(idx);
  265. }
  266. ui->language->model()->sort(0);
  267. }
  268. void OBSBasicSettings::LoadGeneralSettings()
  269. {
  270. loading = true;
  271. LoadLanguageList();
  272. loading = false;
  273. }
  274. void OBSBasicSettings::LoadStream1Settings()
  275. {
  276. QLayout *layout = ui->streamContainer->layout();
  277. obs_service_t *service = main->GetService();
  278. const char *type = obs_service_get_type(service);
  279. loading = true;
  280. obs_data_t *settings = obs_service_get_settings(service);
  281. delete streamProperties;
  282. streamProperties = new OBSPropertiesView(settings, type,
  283. (PropertiesReloadCallback)obs_get_service_properties,
  284. 170);
  285. streamProperties->setProperty("changed", QVariant(false));
  286. layout->addWidget(streamProperties);
  287. QObject::connect(streamProperties, SIGNAL(Changed()),
  288. this, STREAM1_CHANGED);
  289. obs_data_release(settings);
  290. loading = false;
  291. if (main->StreamingActive()) {
  292. ui->streamType->setEnabled(false);
  293. ui->streamContainer->setEnabled(false);
  294. }
  295. }
  296. void OBSBasicSettings::LoadRendererList()
  297. {
  298. const char *renderer = config_get_string(GetGlobalConfig(), "Video",
  299. "Renderer");
  300. #ifdef _WIN32
  301. ui->renderer->addItem(QT_UTF8("Direct3D 11"));
  302. #endif
  303. ui->renderer->addItem(QT_UTF8("OpenGL"));
  304. int idx = ui->renderer->findText(QT_UTF8(renderer));
  305. if (idx == -1)
  306. idx = 0;
  307. ui->renderer->setCurrentIndex(idx);
  308. }
  309. Q_DECLARE_METATYPE(MonitorInfo);
  310. static string ResString(uint32_t cx, uint32_t cy)
  311. {
  312. stringstream res;
  313. res << cx << "x" << cy;
  314. return res.str();
  315. }
  316. /* some nice default output resolution vals */
  317. static const double vals[] =
  318. {
  319. 1.0,
  320. 1.25,
  321. (1.0/0.75),
  322. 1.5,
  323. (1.0/0.6),
  324. 1.75,
  325. 2.0,
  326. 2.25,
  327. 2.5,
  328. 2.75,
  329. 3.0
  330. };
  331. static const size_t numVals = sizeof(vals)/sizeof(double);
  332. void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy)
  333. {
  334. QString advRescale;
  335. QString advRecRescale;
  336. QString advFFRescale;
  337. advRescale = ui->advOutRescale->lineEdit()->text();
  338. advRecRescale = ui->advOutRecRescale->lineEdit()->text();
  339. advFFRescale = ui->advOutFFRescale->lineEdit()->text();
  340. ui->outputResolution->clear();
  341. ui->advOutRescale->clear();
  342. ui->advOutRecRescale->clear();
  343. ui->advOutFFRescale->clear();
  344. for (size_t idx = 0; idx < numVals; idx++) {
  345. uint32_t downscaleCX = uint32_t(double(cx) / vals[idx]);
  346. uint32_t downscaleCY = uint32_t(double(cy) / vals[idx]);
  347. string res = ResString(downscaleCX, downscaleCY);
  348. ui->outputResolution->addItem(res.c_str());
  349. ui->advOutRescale->addItem(res.c_str());
  350. ui->advOutRecRescale->addItem(res.c_str());
  351. ui->advOutFFRescale->addItem(res.c_str());
  352. }
  353. string res = ResString(cx, cy);
  354. ui->outputResolution->lineEdit()->setText(res.c_str());
  355. if (advRescale.isEmpty())
  356. advRescale = res.c_str();
  357. if (advRecRescale.isEmpty())
  358. advRecRescale = res.c_str();
  359. if (advFFRescale.isEmpty())
  360. advFFRescale = res.c_str();
  361. ui->advOutRescale->lineEdit()->setText(advRescale);
  362. ui->advOutRecRescale->lineEdit()->setText(advRecRescale);
  363. ui->advOutFFRescale->lineEdit()->setText(advFFRescale);
  364. }
  365. void OBSBasicSettings::LoadDownscaleFilters()
  366. {
  367. ui->downscaleFilter->addItem(
  368. QTStr("Basic.Settings.Video.DownscaleFilter.Bilinear"),
  369. QT_UTF8("bilinear"));
  370. ui->downscaleFilter->addItem(
  371. QTStr("Basic.Settings.Video.DownscaleFilter.Bicubic"),
  372. QT_UTF8("bicubic"));
  373. ui->downscaleFilter->addItem(
  374. QTStr("Basic.Settings.Video.DownscaleFilter.Lanczos"),
  375. QT_UTF8("lanczos"));
  376. const char *scaleType = config_get_string(main->Config(),
  377. "Video", "ScaleType");
  378. if (astrcmpi(scaleType, "bilinear") == 0)
  379. ui->downscaleFilter->setCurrentIndex(0);
  380. else if (astrcmpi(scaleType, "lanczos") == 0)
  381. ui->downscaleFilter->setCurrentIndex(2);
  382. else
  383. ui->downscaleFilter->setCurrentIndex(1);
  384. }
  385. void OBSBasicSettings::LoadResolutionLists()
  386. {
  387. uint32_t cx = config_get_uint(main->Config(), "Video", "BaseCX");
  388. uint32_t cy = config_get_uint(main->Config(), "Video", "BaseCY");
  389. vector<MonitorInfo> monitors;
  390. ui->baseResolution->clear();
  391. GetMonitors(monitors);
  392. for (MonitorInfo &monitor : monitors) {
  393. string res = ResString(monitor.cx, monitor.cy);
  394. ui->baseResolution->addItem(res.c_str());
  395. }
  396. ResetDownscales(cx, cy);
  397. ui->baseResolution->lineEdit()->setText(ResString(cx, cy).c_str());
  398. cx = config_get_uint(main->Config(), "Video", "OutputCX");
  399. cy = config_get_uint(main->Config(), "Video", "OutputCY");
  400. ui->outputResolution->lineEdit()->setText(ResString(cx, cy).c_str());
  401. }
  402. static inline void LoadFPSCommon(OBSBasic *main, Ui::OBSBasicSettings *ui)
  403. {
  404. const char *val = config_get_string(main->Config(), "Video",
  405. "FPSCommon");
  406. int idx = ui->fpsCommon->findText(val);
  407. if (idx == -1) idx = 3;
  408. ui->fpsCommon->setCurrentIndex(idx);
  409. }
  410. static inline void LoadFPSInteger(OBSBasic *main, Ui::OBSBasicSettings *ui)
  411. {
  412. uint32_t val = config_get_uint(main->Config(), "Video", "FPSInt");
  413. ui->fpsInteger->setValue(val);
  414. }
  415. static inline void LoadFPSFraction(OBSBasic *main, Ui::OBSBasicSettings *ui)
  416. {
  417. uint32_t num = config_get_uint(main->Config(), "Video", "FPSNum");
  418. uint32_t den = config_get_uint(main->Config(), "Video", "FPSDen");
  419. ui->fpsNumerator->setValue(num);
  420. ui->fpsDenominator->setValue(den);
  421. }
  422. void OBSBasicSettings::LoadFPSData()
  423. {
  424. LoadFPSCommon(main, ui.get());
  425. LoadFPSInteger(main, ui.get());
  426. LoadFPSFraction(main, ui.get());
  427. uint32_t fpsType = config_get_uint(main->Config(), "Video",
  428. "FPSType");
  429. if (fpsType > 2) fpsType = 0;
  430. ui->fpsType->setCurrentIndex(fpsType);
  431. ui->fpsTypes->setCurrentIndex(fpsType);
  432. }
  433. void OBSBasicSettings::LoadVideoSettings()
  434. {
  435. loading = true;
  436. if (video_output_active(obs_get_video())) {
  437. ui->videoPage->setEnabled(false);
  438. ui->videoMsg->setText(
  439. QTStr("Basic.Settings.Video.CurrentlyActive"));
  440. }
  441. LoadRendererList();
  442. LoadResolutionLists();
  443. LoadFPSData();
  444. LoadDownscaleFilters();
  445. loading = false;
  446. }
  447. void OBSBasicSettings::LoadSimpleOutputSettings()
  448. {
  449. const char *path = config_get_string(main->Config(), "SimpleOutput",
  450. "FilePath");
  451. int videoBitrate = config_get_uint(main->Config(), "SimpleOutput",
  452. "VBitrate");
  453. int videoBufsize = config_get_uint(main->Config(), "SimpleOutput",
  454. "Bufsize");
  455. int audioBitrate = config_get_uint(main->Config(), "SimpleOutput",
  456. "ABitrate");
  457. bool reconnect = config_get_bool(main->Config(), "SimpleOutput",
  458. "Reconnect");
  459. int retryDelay = config_get_uint(main->Config(), "SimpleOutput",
  460. "RetryDelay");
  461. int maxRetries = config_get_uint(main->Config(), "SimpleOutput",
  462. "MaxRetries");
  463. bool advanced = config_get_bool(main->Config(), "SimpleOutput",
  464. "UseAdvanced");
  465. bool useCBR = config_get_bool(main->Config(), "SimpleOutput",
  466. "UseCBR");
  467. bool useBufsize = config_get_bool(main->Config(), "SimpleOutput",
  468. "UseBufsize");
  469. const char *preset = config_get_string(main->Config(), "SimpleOutput",
  470. "Preset");
  471. const char *custom = config_get_string(main->Config(), "SimpleOutput",
  472. "x264Settings");
  473. ui->simpleOutputPath->setText(path);
  474. ui->simpleOutputVBitrate->setValue(videoBitrate);
  475. ui->simpleOutUseBufsize->setChecked(useBufsize);
  476. ui->simpleOutVBufsize->setValue(
  477. useBufsize ? videoBufsize : videoBitrate);
  478. SetComboByName(ui->simpleOutputABitrate,
  479. std::to_string(audioBitrate).c_str());
  480. ui->simpleOutReconnect->setChecked(reconnect);
  481. ui->simpleOutRetryDelay->setValue(retryDelay);
  482. ui->simpleOutMaxRetries->setValue(maxRetries);
  483. ui->simpleOutAdvanced->setChecked(advanced);
  484. ui->simpleOutUseCBR->setChecked(useCBR);
  485. ui->simpleOutPreset->setCurrentText(preset);
  486. ui->simpleOutCustom->setText(custom);
  487. }
  488. void OBSBasicSettings::LoadAdvOutputStreamingSettings()
  489. {
  490. bool reconnect = config_get_bool(main->Config(), "AdvOut",
  491. "Reconnect");
  492. int retryDelay = config_get_int(main->Config(), "AdvOut",
  493. "RetryDelay");
  494. int maxRetries = config_get_int(main->Config(), "AdvOut",
  495. "MaxRetries");
  496. bool rescale = config_get_bool(main->Config(), "AdvOut",
  497. "Rescale");
  498. const char *rescaleRes = config_get_string(main->Config(), "AdvOut",
  499. "RescaleRes");
  500. int trackIndex = config_get_int(main->Config(), "AdvOut",
  501. "TrackIndex");
  502. ui->advOutReconnect->setChecked(reconnect);
  503. ui->advOutRetryDelay->setValue(retryDelay);
  504. ui->advOutMaxRetries->setValue(maxRetries);
  505. ui->advOutUseRescale->setChecked(rescale);
  506. ui->advOutRescale->setCurrentText(rescaleRes);
  507. switch (trackIndex) {
  508. case 1: ui->advOutTrack1->setChecked(true); break;
  509. case 2: ui->advOutTrack2->setChecked(true); break;
  510. case 3: ui->advOutTrack3->setChecked(true); break;
  511. case 4: ui->advOutTrack4->setChecked(true); break;
  512. }
  513. }
  514. OBSPropertiesView *OBSBasicSettings::CreateEncoderPropertyView(
  515. const char *encoder, const char *path, bool changed)
  516. {
  517. obs_data_t *settings = obs_encoder_defaults(encoder);
  518. OBSPropertiesView *view;
  519. char encoderJsonPath[512];
  520. int ret = os_get_config_path(encoderJsonPath, sizeof(encoderJsonPath),
  521. path);
  522. if (ret > 0) {
  523. BPtr<char> jsonData = os_quick_read_utf8_file(encoderJsonPath);
  524. if (!!jsonData) {
  525. obs_data_t *data = obs_data_create_from_json(jsonData);
  526. obs_data_apply(settings, data);
  527. obs_data_release(data);
  528. }
  529. }
  530. view = new OBSPropertiesView(settings, encoder,
  531. (PropertiesReloadCallback)obs_get_encoder_properties,
  532. 170);
  533. view->setFrameShape(QFrame::StyledPanel);
  534. view->setProperty("changed", QVariant(changed));
  535. QObject::connect(view, SIGNAL(Changed()), this, SLOT(OutputsChanged()));
  536. obs_data_release(settings);
  537. return view;
  538. }
  539. void OBSBasicSettings::LoadAdvOutputStreamingEncoderProperties()
  540. {
  541. const char *encoder = config_get_string(main->Config(), "AdvOut",
  542. "Encoder");
  543. delete streamEncoderProps;
  544. streamEncoderProps = CreateEncoderPropertyView(encoder,
  545. "obs-studio/basic/streamEncoder.json");
  546. ui->advOutputStreamTab->layout()->addWidget(streamEncoderProps);
  547. SetComboByValue(ui->advOutEncoder, encoder);
  548. }
  549. void OBSBasicSettings::LoadAdvOutputRecordingSettings()
  550. {
  551. const char *type = config_get_string(main->Config(), "AdvOut",
  552. "RecType");
  553. const char *path = config_get_string(main->Config(), "AdvOut",
  554. "RecFilePath");
  555. bool rescale = config_get_bool(main->Config(), "AdvOut",
  556. "RecRescale");
  557. const char *rescaleRes = config_get_string(main->Config(), "AdvOut",
  558. "RecRescaleRes");
  559. int trackIndex = config_get_int(main->Config(), "AdvOut",
  560. "RecTrackIndex");
  561. int typeIndex = (astrcmpi(type, "FFmpeg") == 0) ? 1 : 0;
  562. ui->advOutRecType->setCurrentIndex(typeIndex);
  563. ui->advOutRecPath->setText(path);
  564. ui->advOutRecUseRescale->setChecked(rescale);
  565. ui->advOutRecRescale->setCurrentText(rescaleRes);
  566. switch (trackIndex) {
  567. case 1: ui->advOutRecTrack1->setChecked(true); break;
  568. case 2: ui->advOutRecTrack2->setChecked(true); break;
  569. case 3: ui->advOutRecTrack3->setChecked(true); break;
  570. case 4: ui->advOutRecTrack4->setChecked(true); break;
  571. }
  572. }
  573. void OBSBasicSettings::LoadAdvOutputRecordingEncoderProperties()
  574. {
  575. const char *encoder = config_get_string(main->Config(), "AdvOut",
  576. "RecEncoder");
  577. delete recordEncoderProps;
  578. recordEncoderProps = nullptr;
  579. if (astrcmpi(encoder, "none") != 0) {
  580. recordEncoderProps = CreateEncoderPropertyView(encoder,
  581. "obs-studio/basic/recordEncoder.json");
  582. ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
  583. }
  584. SetComboByValue(ui->advOutRecEncoder, encoder);
  585. }
  586. void OBSBasicSettings::LoadAdvOutputFFmpegSettings()
  587. {
  588. const char *url = config_get_string(main->Config(), "AdvOut", "FFURL");
  589. int videoBitrate = config_get_int(main->Config(), "AdvOut",
  590. "FFVBitrate");
  591. bool rescale = config_get_bool(main->Config(), "AdvOut",
  592. "FFRescale");
  593. const char *rescaleRes = config_get_string(main->Config(), "AdvOut",
  594. "FFRescaleRes");
  595. const char *vEncoder = config_get_string(main->Config(), "AdvOut",
  596. "FFVEncoder");
  597. const char *vEncCustom = config_get_string(main->Config(), "AdvOut",
  598. "FFVCustom");
  599. int audioBitrate = config_get_int(main->Config(), "AdvOut",
  600. "FFABitrate");
  601. int audioTrack = config_get_int(main->Config(), "AdvOut",
  602. "FFAudioTrack");
  603. const char *aEncoder = config_get_string(main->Config(), "AdvOut",
  604. "FFAEncoder");
  605. const char *aEncCustom = config_get_string(main->Config(), "AdvOut",
  606. "FFACustom");
  607. ui->advOutFFURL->setText(url);
  608. ui->advOutFFVBitrate->setValue(videoBitrate);
  609. ui->advOutFFUseRescale->setChecked(rescale);
  610. ui->advOutFFRescale->setCurrentText(rescaleRes);
  611. ui->advOutFFVEncoder->setText(vEncoder);
  612. ui->advOutFFVCfg->setText(vEncCustom);
  613. ui->advOutFFABitrate->setValue(audioBitrate);
  614. ui->advOutFFAEncoder->setText(aEncoder);
  615. ui->advOutFFACfg->setText(aEncCustom);
  616. switch (audioTrack) {
  617. case 1: ui->advOutFFTrack1->setChecked(true); break;
  618. case 2: ui->advOutFFTrack2->setChecked(true); break;
  619. case 3: ui->advOutFFTrack3->setChecked(true); break;
  620. case 4: ui->advOutFFTrack4->setChecked(true); break;
  621. }
  622. }
  623. void OBSBasicSettings::LoadAdvOutputAudioSettings()
  624. {
  625. int track1Bitrate = config_get_uint(main->Config(), "AdvOut",
  626. "Track1Bitrate");
  627. int track2Bitrate = config_get_uint(main->Config(), "AdvOut",
  628. "Track2Bitrate");
  629. int track3Bitrate = config_get_uint(main->Config(), "AdvOut",
  630. "Track3Bitrate");
  631. int track4Bitrate = config_get_uint(main->Config(), "AdvOut",
  632. "Track4Bitrate");
  633. const char *name1 = config_get_string(main->Config(), "AdvOut",
  634. "Track1Name");
  635. const char *name2 = config_get_string(main->Config(), "AdvOut",
  636. "Track2Name");
  637. const char *name3 = config_get_string(main->Config(), "AdvOut",
  638. "Track3Name");
  639. const char *name4 = config_get_string(main->Config(), "AdvOut",
  640. "Track4Name");
  641. SetComboByName(ui->advOutTrack1Bitrate,
  642. std::to_string(track1Bitrate).c_str());
  643. SetComboByName(ui->advOutTrack2Bitrate,
  644. std::to_string(track2Bitrate).c_str());
  645. SetComboByName(ui->advOutTrack3Bitrate,
  646. std::to_string(track3Bitrate).c_str());
  647. SetComboByName(ui->advOutTrack4Bitrate,
  648. std::to_string(track4Bitrate).c_str());
  649. ui->advOutTrack1Name->setText(name1);
  650. ui->advOutTrack2Name->setText(name2);
  651. ui->advOutTrack3Name->setText(name3);
  652. ui->advOutTrack4Name->setText(name4);
  653. }
  654. void OBSBasicSettings::LoadOutputSettings()
  655. {
  656. loading = true;
  657. const char *mode = config_get_string(main->Config(), "Output", "Mode");
  658. int modeIdx = astrcmpi(mode, "Advanced") == 0 ? 1 : 0;
  659. ui->outputMode->setCurrentIndex(modeIdx);
  660. LoadSimpleOutputSettings();
  661. LoadAdvOutputStreamingSettings();
  662. LoadAdvOutputStreamingEncoderProperties();
  663. LoadAdvOutputRecordingSettings();
  664. LoadAdvOutputRecordingEncoderProperties();
  665. LoadAdvOutputFFmpegSettings();
  666. LoadAdvOutputAudioSettings();
  667. if (video_output_active(obs_get_video())) {
  668. ui->outputMode->setEnabled(false);
  669. ui->advOutTopContainer->setEnabled(false);
  670. ui->advOutRecTopContainer->setEnabled(false);
  671. ui->advOutRecTypeContainer->setEnabled(false);
  672. ui->advOutputAudioTracksTab->setEnabled(false);
  673. }
  674. loading = false;
  675. }
  676. static inline void LoadListValue(QComboBox *widget, const char *text,
  677. const char *val)
  678. {
  679. widget->addItem(QT_UTF8(text), QT_UTF8(val));
  680. }
  681. void OBSBasicSettings::LoadListValues(QComboBox *widget, obs_property_t *prop,
  682. const char *configName)
  683. {
  684. size_t count = obs_property_list_item_count(prop);
  685. const char *deviceId = config_get_string(main->Config(), "Audio",
  686. configName);
  687. widget->addItem(QTStr("Disabled"), "disabled");
  688. for (size_t i = 0; i < count; i++) {
  689. const char *name = obs_property_list_item_name(prop, i);
  690. const char *val = obs_property_list_item_string(prop, i);
  691. LoadListValue(widget, name, val);
  692. }
  693. int idx = widget->findData(QVariant(QT_UTF8(deviceId)));
  694. if (idx == -1) {
  695. deviceId = config_get_default_string(main->Config(), "Audio",
  696. configName);
  697. idx = widget->findData(QVariant(QT_UTF8(deviceId)));
  698. }
  699. if (idx != -1)
  700. widget->setCurrentIndex(idx);
  701. }
  702. void OBSBasicSettings::LoadAudioDevices()
  703. {
  704. const char *input_id = App()->InputAudioSource();
  705. const char *output_id = App()->OutputAudioSource();
  706. obs_properties_t *input_props = obs_get_source_properties(
  707. OBS_SOURCE_TYPE_INPUT, input_id);
  708. obs_properties_t *output_props = obs_get_source_properties(
  709. OBS_SOURCE_TYPE_INPUT, output_id);
  710. if (input_props) {
  711. obs_property_t *inputs = obs_properties_get(input_props,
  712. "device_id");
  713. LoadListValues(ui->auxAudioDevice1, inputs, "AuxDevice1");
  714. LoadListValues(ui->auxAudioDevice2, inputs, "AuxDevice2");
  715. LoadListValues(ui->auxAudioDevice3, inputs, "AuxDevice3");
  716. obs_properties_destroy(input_props);
  717. }
  718. if (output_props) {
  719. obs_property_t *outputs = obs_properties_get(output_props,
  720. "device_id");
  721. LoadListValues(ui->desktopAudioDevice1, outputs,
  722. "DesktopDevice1");
  723. LoadListValues(ui->desktopAudioDevice2, outputs,
  724. "DesktopDevice2");
  725. obs_properties_destroy(output_props);
  726. }
  727. }
  728. void OBSBasicSettings::LoadAudioSettings()
  729. {
  730. uint32_t sampleRate = config_get_uint(main->Config(), "Audio",
  731. "SampleRate");
  732. const char *speakers = config_get_string(main->Config(), "Audio",
  733. "ChannelSetup");
  734. loading = true;
  735. const char *str;
  736. if (sampleRate == 22050)
  737. str = "22.05khz";
  738. else if (sampleRate == 48000)
  739. str = "48khz";
  740. else
  741. str = "44.1khz";
  742. int sampleRateIdx = ui->sampleRate->findText(str);
  743. if (sampleRateIdx != -1)
  744. ui->sampleRate->setCurrentIndex(sampleRateIdx);
  745. if (strcmp(speakers, "Mono") == 0)
  746. ui->channelSetup->setCurrentIndex(0);
  747. else
  748. ui->channelSetup->setCurrentIndex(1);
  749. LoadAudioDevices();
  750. loading = false;
  751. }
  752. void OBSBasicSettings::LoadSettings(bool changedOnly)
  753. {
  754. if (!changedOnly || generalChanged)
  755. LoadGeneralSettings();
  756. if (!changedOnly || stream1Changed)
  757. LoadStream1Settings();
  758. if (!changedOnly || outputsChanged)
  759. LoadOutputSettings();
  760. if (!changedOnly || audioChanged)
  761. LoadAudioSettings();
  762. if (!changedOnly || videoChanged)
  763. LoadVideoSettings();
  764. }
  765. void OBSBasicSettings::SaveGeneralSettings()
  766. {
  767. int languageIndex = ui->language->currentIndex();
  768. QVariant langData = ui->language->itemData(languageIndex);
  769. string language = langData.toString().toStdString();
  770. if (WidgetChanged(ui->language))
  771. config_set_string(GetGlobalConfig(), "General", "Language",
  772. language.c_str());
  773. }
  774. void OBSBasicSettings::SaveStream1Settings()
  775. {
  776. QString streamType = GetComboData(ui->streamType);
  777. obs_service_t *newService = obs_service_create(QT_TO_UTF8(streamType),
  778. "default_service", streamProperties->GetSettings());
  779. if (!newService)
  780. return;
  781. main->SetService(newService);
  782. main->SaveService();
  783. }
  784. void OBSBasicSettings::SaveVideoSettings()
  785. {
  786. QString baseResolution = ui->baseResolution->currentText();
  787. QString outputResolution = ui->outputResolution->currentText();
  788. int fpsType = ui->fpsType->currentIndex();
  789. uint32_t cx = 0, cy = 0;
  790. /* ------------------- */
  791. if (WidgetChanged(ui->renderer))
  792. config_set_string(App()->GlobalConfig(), "Video", "Renderer",
  793. QT_TO_UTF8(ui->renderer->currentText()));
  794. if (WidgetChanged(ui->baseResolution) &&
  795. ConvertResText(QT_TO_UTF8(baseResolution), cx, cy)) {
  796. config_set_uint(main->Config(), "Video", "BaseCX", cx);
  797. config_set_uint(main->Config(), "Video", "BaseCY", cy);
  798. }
  799. if (WidgetChanged(ui->outputResolution) &&
  800. ConvertResText(QT_TO_UTF8(outputResolution), cx, cy)) {
  801. config_set_uint(main->Config(), "Video", "OutputCX", cx);
  802. config_set_uint(main->Config(), "Video", "OutputCY", cy);
  803. }
  804. if (WidgetChanged(ui->fpsType))
  805. config_set_uint(main->Config(), "Video", "FPSType", fpsType);
  806. SaveCombo(ui->fpsCommon, "Video", "FPSCommon");
  807. SaveSpinBox(ui->fpsInteger, "Video", "FPSInt");
  808. SaveSpinBox(ui->fpsNumerator, "Video", "FPSNum");
  809. SaveSpinBox(ui->fpsDenominator, "Video", "FPSDen");
  810. SaveComboData(ui->downscaleFilter, "Video", "ScaleType");
  811. main->ResetVideo();
  812. }
  813. static inline const char *OutputModeFromIdx(int idx)
  814. {
  815. if (idx == 1)
  816. return "Advanced";
  817. else
  818. return "Simple";
  819. }
  820. static inline const char *RecTypeFromIdx(int idx)
  821. {
  822. if (idx == 1)
  823. return "FFmpeg";
  824. else
  825. return "Standard";
  826. }
  827. static void WriteJsonData(OBSPropertiesView *view, const char *path)
  828. {
  829. char full_path[512];
  830. if (!view || !WidgetChanged(view))
  831. return;
  832. int ret = os_get_config_path(full_path, sizeof(full_path), path);
  833. if (ret > 0) {
  834. obs_data_t *settings = view->GetSettings();
  835. if (settings) {
  836. const char *json = obs_data_get_json(settings);
  837. if (json && *json) {
  838. os_quick_write_utf8_file(full_path, json,
  839. strlen(json), false);
  840. }
  841. }
  842. }
  843. }
  844. static void SaveTrackIndex(config_t *config, const char *section,
  845. const char *name,
  846. QAbstractButton *check1,
  847. QAbstractButton *check2,
  848. QAbstractButton *check3,
  849. QAbstractButton *check4)
  850. {
  851. if (check1->isChecked()) config_set_int(config, section, name, 1);
  852. else if (check2->isChecked()) config_set_int(config, section, name, 2);
  853. else if (check3->isChecked()) config_set_int(config, section, name, 3);
  854. else if (check4->isChecked()) config_set_int(config, section, name, 4);
  855. }
  856. void OBSBasicSettings::SaveOutputSettings()
  857. {
  858. config_set_string(main->Config(), "Output", "Mode",
  859. OutputModeFromIdx(ui->outputMode->currentIndex()));
  860. SaveSpinBox(ui->simpleOutputVBitrate, "SimpleOutput", "VBitrate");
  861. SaveCombo(ui->simpleOutputABitrate, "SimpleOutput", "ABitrate");
  862. SaveEdit(ui->simpleOutputPath, "SimpleOutput", "FilePath");
  863. SaveCheckBox(ui->simpleOutReconnect, "SimpleOutput", "Reconnect");
  864. SaveSpinBox(ui->simpleOutRetryDelay, "SimpleOutput", "RetryDelay");
  865. SaveSpinBox(ui->simpleOutMaxRetries, "SimpleOutput", "MaxRetries");
  866. SaveCheckBox(ui->simpleOutAdvanced, "SimpleOutput", "UseAdvanced");
  867. SaveCheckBox(ui->simpleOutUseCBR, "SimpleOutput", "UseCBR");
  868. SaveCheckBox(ui->simpleOutUseBufsize, "SimpleOutput", "UseBufsize");
  869. SaveCombo(ui->simpleOutPreset, "SimpleOutput", "Preset");
  870. SaveEdit(ui->simpleOutCustom, "SimpleOutput", "x264Settings");
  871. if (ui->simpleOutUseBufsize->isChecked())
  872. SaveSpinBox(ui->simpleOutVBufsize, "SimpleOutput", "VBufsize");
  873. SaveCheckBox(ui->advOutReconnect, "AdvOut", "Reconnect");
  874. SaveSpinBox(ui->advOutRetryDelay, "AdvOut", "RetryDelay");
  875. SaveSpinBox(ui->advOutMaxRetries, "AdvOut", "MaxRetries");
  876. SaveComboData(ui->advOutEncoder, "AdvOut", "Encoder");
  877. SaveCheckBox(ui->advOutUseRescale, "AdvOut", "Rescale");
  878. SaveCombo(ui->advOutRescale, "AdvOut", "RescaleRes");
  879. SaveTrackIndex(main->Config(), "AdvOut", "TrackIndex",
  880. ui->advOutTrack1, ui->advOutTrack2,
  881. ui->advOutTrack3, ui->advOutTrack4);
  882. config_set_string(main->Config(), "AdvOut", "RecType",
  883. RecTypeFromIdx(ui->advOutRecType->currentIndex()));
  884. SaveEdit(ui->advOutRecPath, "AdvOut", "RecFilePath");
  885. SaveComboData(ui->advOutRecEncoder, "AdvOut", "RecEncoder");
  886. SaveCheckBox(ui->advOutRecUseRescale, "AdvOut", "RecRescale");
  887. SaveCombo(ui->advOutRecRescale, "AdvOut", "RecRescaleRes");
  888. SaveTrackIndex(main->Config(), "AdvOut", "RecTrackIndex",
  889. ui->advOutRecTrack1, ui->advOutRecTrack2,
  890. ui->advOutRecTrack3, ui->advOutRecTrack4);
  891. SaveEdit(ui->advOutFFURL, "AdvOut", "FFURL");
  892. SaveSpinBox(ui->advOutFFVBitrate, "AdvOut", "FFVBitrate");
  893. SaveCheckBox(ui->advOutFFUseRescale, "AdvOut", "FFRescale");
  894. SaveCombo(ui->advOutFFRescale, "AdvOut", "FFRescaleRes");
  895. SaveEdit(ui->advOutFFVEncoder, "AdvOut", "FFVEncoder");
  896. SaveEdit(ui->advOutFFVCfg, "AdvOut", "FFVCustom");
  897. SaveSpinBox(ui->advOutFFABitrate, "AdvOut", "FFABitrate");
  898. SaveEdit(ui->advOutFFAEncoder, "AdvOut", "FFAEncoder");
  899. SaveEdit(ui->advOutFFACfg, "AdvOut", "FFACustom");
  900. SaveTrackIndex(main->Config(), "AdvOut", "FFAudioTrack",
  901. ui->advOutFFTrack1, ui->advOutFFTrack2,
  902. ui->advOutFFTrack3, ui->advOutFFTrack4);
  903. SaveCombo(ui->advOutTrack1Bitrate, "AdvOut", "Track1Bitrate");
  904. SaveCombo(ui->advOutTrack2Bitrate, "AdvOut", "Track2Bitrate");
  905. SaveCombo(ui->advOutTrack3Bitrate, "AdvOut", "Track3Bitrate");
  906. SaveCombo(ui->advOutTrack4Bitrate, "AdvOut", "Track4Bitrate");
  907. SaveEdit(ui->advOutTrack1Name, "AdvOut", "Track1Name");
  908. SaveEdit(ui->advOutTrack2Name, "AdvOut", "Track2Name");
  909. SaveEdit(ui->advOutTrack3Name, "AdvOut", "Track3Name");
  910. SaveEdit(ui->advOutTrack4Name, "AdvOut", "Track4Name");
  911. WriteJsonData(streamEncoderProps,
  912. "obs-studio/basic/streamEncoder.json");
  913. WriteJsonData(recordEncoderProps,
  914. "obs-studio/basic/recordEncoder.json");
  915. main->ResetOutputs();
  916. }
  917. void OBSBasicSettings::SaveAudioSettings()
  918. {
  919. QString sampleRateStr = ui->sampleRate->currentText();
  920. int channelSetupIdx = ui->channelSetup->currentIndex();
  921. const char *channelSetup = (channelSetupIdx == 0) ? "Mono" : "Stereo";
  922. int sampleRate = 44100;
  923. if (sampleRateStr == "22.05khz")
  924. sampleRate = 22050;
  925. else if (sampleRateStr == "48khz")
  926. sampleRate = 48000;
  927. if (WidgetChanged(ui->sampleRate))
  928. config_set_uint(main->Config(), "Audio", "SampleRate",
  929. sampleRate);
  930. if (WidgetChanged(ui->channelSetup))
  931. config_set_string(main->Config(), "Audio", "ChannelSetup",
  932. channelSetup);
  933. SaveComboData(ui->desktopAudioDevice1, "Audio", "DesktopDevice1");
  934. SaveComboData(ui->desktopAudioDevice2, "Audio", "DesktopDevice2");
  935. SaveComboData(ui->auxAudioDevice1, "Audio", "AuxDevice1");
  936. SaveComboData(ui->auxAudioDevice2, "Audio", "AuxDevice2");
  937. SaveComboData(ui->auxAudioDevice3, "Audio", "AuxDevice3");
  938. main->ResetAudioDevices();
  939. }
  940. void OBSBasicSettings::SaveSettings()
  941. {
  942. if (generalChanged)
  943. SaveGeneralSettings();
  944. if (stream1Changed)
  945. SaveStream1Settings();
  946. if (outputsChanged)
  947. SaveOutputSettings();
  948. if (audioChanged)
  949. SaveAudioSettings();
  950. if (videoChanged)
  951. SaveVideoSettings();
  952. config_save(main->Config());
  953. config_save(GetGlobalConfig());
  954. }
  955. bool OBSBasicSettings::QueryChanges()
  956. {
  957. QMessageBox::StandardButton button;
  958. button = QMessageBox::question(this,
  959. QTStr("Basic.Settings.ConfirmTitle"),
  960. QTStr("Basic.Settings.Confirm"),
  961. QMessageBox::Yes | QMessageBox::No |
  962. QMessageBox::Cancel);
  963. if (button == QMessageBox::Cancel)
  964. return false;
  965. else if (button == QMessageBox::Yes)
  966. SaveSettings();
  967. else
  968. LoadSettings(true);
  969. ClearChanged();
  970. return true;
  971. }
  972. void OBSBasicSettings::closeEvent(QCloseEvent *event)
  973. {
  974. if (Changed() && !QueryChanges())
  975. event->ignore();
  976. }
  977. void OBSBasicSettings::on_simpleOutUseBufsize_toggled(bool checked)
  978. {
  979. if (!checked)
  980. ui->simpleOutVBufsize->setValue(
  981. ui->simpleOutputVBitrate->value());
  982. }
  983. void OBSBasicSettings::on_simpleOutputVBitrate_valueChanged(int val)
  984. {
  985. if (!ui->simpleOutUseBufsize->isChecked())
  986. ui->simpleOutVBufsize->setValue(val);
  987. }
  988. void OBSBasicSettings::on_listWidget_itemSelectionChanged()
  989. {
  990. int row = ui->listWidget->currentRow();
  991. if (loading || row == pageIndex)
  992. return;
  993. pageIndex = row;
  994. }
  995. void OBSBasicSettings::on_buttonBox_clicked(QAbstractButton *button)
  996. {
  997. QDialogButtonBox::ButtonRole val = ui->buttonBox->buttonRole(button);
  998. if (val == QDialogButtonBox::ApplyRole ||
  999. val == QDialogButtonBox::AcceptRole) {
  1000. SaveSettings();
  1001. ClearChanged();
  1002. }
  1003. if (val == QDialogButtonBox::AcceptRole ||
  1004. val == QDialogButtonBox::RejectRole) {
  1005. ClearChanged();
  1006. close();
  1007. }
  1008. }
  1009. void OBSBasicSettings::on_streamType_currentIndexChanged(int idx)
  1010. {
  1011. if (loading)
  1012. return;
  1013. QLayout *layout = ui->streamContainer->layout();
  1014. QString streamType = ui->streamType->itemData(idx).toString();
  1015. obs_data_t *settings = obs_service_defaults(QT_TO_UTF8(streamType));
  1016. delete streamProperties;
  1017. streamProperties = new OBSPropertiesView(settings,
  1018. QT_TO_UTF8(streamType),
  1019. (PropertiesReloadCallback)obs_get_service_properties,
  1020. 170);
  1021. streamProperties->setProperty("changed", QVariant(true));
  1022. layout->addWidget(streamProperties);
  1023. QObject::connect(streamProperties, SIGNAL(Changed()),
  1024. this, STREAM1_CHANGED);
  1025. obs_data_release(settings);
  1026. }
  1027. void OBSBasicSettings::on_simpleOutputBrowse_clicked()
  1028. {
  1029. QString dir = QFileDialog::getExistingDirectory(this,
  1030. QTStr("Basic.Settings.Output.SelectDirectory"),
  1031. ui->simpleOutputPath->text(),
  1032. QFileDialog::ShowDirsOnly |
  1033. QFileDialog::DontResolveSymlinks);
  1034. if (dir.isEmpty())
  1035. return;
  1036. ui->simpleOutputPath->setText(dir);
  1037. }
  1038. void OBSBasicSettings::on_advOutRecPathBrowse_clicked()
  1039. {
  1040. QString dir = QFileDialog::getExistingDirectory(this,
  1041. QTStr("Basic.Settings.Output.SelectDirectory"),
  1042. ui->advOutRecPath->text(),
  1043. QFileDialog::ShowDirsOnly |
  1044. QFileDialog::DontResolveSymlinks);
  1045. if (dir.isEmpty())
  1046. return;
  1047. ui->advOutRecPath->setText(dir);
  1048. }
  1049. void OBSBasicSettings::on_advOutFFPathBrowse_clicked()
  1050. {
  1051. QString file = QFileDialog::getSaveFileName(this,
  1052. QTStr("Basic.Settings.Output.SelectFile"),
  1053. ui->simpleOutputPath->text(),
  1054. QTStr("Basic.Settings.Output.Adv.FFmpeg.SaveFilter"));
  1055. if (file.isEmpty())
  1056. return;
  1057. ui->advOutFFURL->setText(file);
  1058. }
  1059. void OBSBasicSettings::on_advOutEncoder_currentIndexChanged(int idx)
  1060. {
  1061. QString encoder = GetComboData(ui->advOutEncoder);
  1062. delete streamEncoderProps;
  1063. streamEncoderProps = CreateEncoderPropertyView(QT_TO_UTF8(encoder),
  1064. "obs-studio/basic/streamEncoder.json", true);
  1065. ui->advOutputStreamTab->layout()->addWidget(streamEncoderProps);
  1066. UNUSED_PARAMETER(idx);
  1067. }
  1068. void OBSBasicSettings::on_advOutRecEncoder_currentIndexChanged(int idx)
  1069. {
  1070. ui->advOutRecUseRescale->setEnabled(idx > 0);
  1071. ui->advOutRecRescaleContainer->setEnabled(idx > 0);
  1072. delete recordEncoderProps;
  1073. recordEncoderProps = nullptr;
  1074. if (idx > 0) {
  1075. QString encoder = GetComboData(ui->advOutRecEncoder);
  1076. recordEncoderProps = CreateEncoderPropertyView(
  1077. QT_TO_UTF8(encoder),
  1078. "obs-studio/basic/recordEncoder.json", true);
  1079. ui->advOutRecStandard->layout()->addWidget(recordEncoderProps);
  1080. }
  1081. }
  1082. #define INVALID_RES_STR "Basic.Settings.Video.InvalidResolution"
  1083. static bool ValidResolutions(Ui::OBSBasicSettings *ui)
  1084. {
  1085. QString baseRes = ui->baseResolution->lineEdit()->text();
  1086. QString outputRes = ui->outputResolution->lineEdit()->text();
  1087. uint32_t cx, cy;
  1088. if (!ConvertResText(QT_TO_UTF8(baseRes), cx, cy) ||
  1089. !ConvertResText(QT_TO_UTF8(outputRes), cx, cy)) {
  1090. ui->videoMsg->setText(QTStr(INVALID_RES_STR));
  1091. return false;
  1092. }
  1093. ui->videoMsg->setText("");
  1094. return true;
  1095. }
  1096. void OBSBasicSettings::on_baseResolution_editTextChanged(const QString &text)
  1097. {
  1098. if (!loading && ValidResolutions(ui.get())) {
  1099. QString baseResolution = text;
  1100. uint32_t cx, cy;
  1101. ConvertResText(QT_TO_UTF8(baseResolution), cx, cy);
  1102. ResetDownscales(cx, cy);
  1103. }
  1104. }
  1105. void OBSBasicSettings::GeneralChanged()
  1106. {
  1107. if (!loading) {
  1108. generalChanged = true;
  1109. sender()->setProperty("changed", QVariant(true));
  1110. EnableApplyButton(true);
  1111. }
  1112. }
  1113. void OBSBasicSettings::Stream1Changed()
  1114. {
  1115. if (!loading) {
  1116. stream1Changed = true;
  1117. sender()->setProperty("changed", QVariant(true));
  1118. EnableApplyButton(true);
  1119. }
  1120. }
  1121. void OBSBasicSettings::OutputsChanged()
  1122. {
  1123. if (!loading) {
  1124. outputsChanged = true;
  1125. sender()->setProperty("changed", QVariant(true));
  1126. EnableApplyButton(true);
  1127. }
  1128. }
  1129. void OBSBasicSettings::AudioChanged()
  1130. {
  1131. if (!loading) {
  1132. audioChanged = true;
  1133. sender()->setProperty("changed", QVariant(true));
  1134. EnableApplyButton(true);
  1135. }
  1136. }
  1137. void OBSBasicSettings::AudioChangedRestart()
  1138. {
  1139. if (!loading) {
  1140. audioChanged = true;
  1141. ui->audioMsg->setText(QTStr("Basic.Settings.ProgramRestart"));
  1142. sender()->setProperty("changed", QVariant(true));
  1143. EnableApplyButton(true);
  1144. }
  1145. }
  1146. void OBSBasicSettings::VideoChangedRestart()
  1147. {
  1148. if (!loading) {
  1149. videoChanged = true;
  1150. ui->videoMsg->setText(QTStr("Basic.Settings.ProgramRestart"));
  1151. sender()->setProperty("changed", QVariant(true));
  1152. EnableApplyButton(true);
  1153. }
  1154. }
  1155. void OBSBasicSettings::VideoChangedResolution()
  1156. {
  1157. if (!loading && ValidResolutions(ui.get())) {
  1158. videoChanged = true;
  1159. sender()->setProperty("changed", QVariant(true));
  1160. EnableApplyButton(true);
  1161. }
  1162. }
  1163. void OBSBasicSettings::VideoChanged()
  1164. {
  1165. if (!loading) {
  1166. videoChanged = true;
  1167. sender()->setProperty("changed", QVariant(true));
  1168. EnableApplyButton(true);
  1169. }
  1170. }