settings-basic-video.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /******************************************************************************
  2. Copyright (C) 2013 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 <util/lexer.h>
  15. #include "obs-app.hpp"
  16. #include "settings-basic.hpp"
  17. #include "window-settings-basic.hpp"
  18. #include "wx-wrappers.hpp"
  19. #include "platform.hpp"
  20. #include <sstream>
  21. using namespace std;
  22. class BasicVideoData : public BasicSettingsData {
  23. ConnectorList connections;
  24. int AddRes(uint32_t cx, uint32_t cy);
  25. void LoadResolutionData();
  26. void LoadFPSData();
  27. void LoadFPSCommon();
  28. void LoadFPSInteger();
  29. void LoadFPSFraction();
  30. void LoadFPSNanoseconds();
  31. void ResetScaleList(uint32_t cx, uint32_t cy);
  32. void BaseResListChanged(wxCommandEvent &event);
  33. void OutputResListChanged(wxCommandEvent &event);
  34. void SaveFPSData();
  35. void SaveFPSCommon();
  36. void SaveFPSInteger();
  37. void SaveFPSFraction();
  38. void SaveFPSNanoseconds();
  39. public:
  40. BasicVideoData(OBSBasicSettings *window);
  41. void Apply();
  42. };
  43. struct BaseLexer {
  44. lexer lex;
  45. public:
  46. inline BaseLexer() {lexer_init(&lex);}
  47. inline ~BaseLexer() {lexer_free(&lex);}
  48. operator lexer*() {return &lex;}
  49. };
  50. /* parses "[width]x[height]", string, i.e. 1024x768 */
  51. static bool ConvertTextRes(wxComboBox *combo, uint32_t &cx, uint32_t &cy)
  52. {
  53. string str = combo->GetValue().ToStdString();
  54. BaseLexer lex;
  55. lexer_start(lex, str.c_str());
  56. base_token token;
  57. /* parse width */
  58. if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  59. return false;
  60. if (token.type != BASETOKEN_DIGIT)
  61. return false;
  62. cx = std::stoul(token.text.array);
  63. /* parse 'x' */
  64. if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  65. return false;
  66. if (strref_cmpi(&token.text, "x") != 0)
  67. return false;
  68. /* parse height */
  69. if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  70. return false;
  71. if (token.type != BASETOKEN_DIGIT)
  72. return false;
  73. cy = std::stoul(token.text.array);
  74. /* shouldn't be any more tokens after this */
  75. if (lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
  76. return false;
  77. return true;
  78. }
  79. int BasicVideoData::AddRes(uint32_t cx, uint32_t cy)
  80. {
  81. stringstream res;
  82. res << cx << "x" << cy;
  83. return window->baseResList->Append(res.str().c_str());
  84. }
  85. void BasicVideoData::LoadResolutionData()
  86. {
  87. window->baseResList->Clear();
  88. uint32_t cx = config_get_uint(GetGlobalConfig(), "Video", "BaseCX");
  89. uint32_t cy = config_get_uint(GetGlobalConfig(), "Video", "BaseCY");
  90. vector<MonitorInfo> monitors;
  91. GetMonitors(monitors);
  92. for (size_t i = 0; i < monitors.size(); i++)
  93. AddRes(monitors[i].cx, monitors[i].cy);
  94. stringstream res;
  95. res << cx << "x" << cy;
  96. window->baseResList->SetValue(res.str());
  97. ResetScaleList(cx, cy);
  98. cx = config_get_uint(GetGlobalConfig(), "Video", "OutputCX");
  99. cy = config_get_uint(GetGlobalConfig(), "Video", "OutputCY");
  100. res.str(string());
  101. res.clear();
  102. res << cx << "x" << cy;
  103. window->outputResList->SetValue(res.str());
  104. }
  105. void BasicVideoData::LoadFPSData()
  106. {
  107. const char *fpsType = config_get_string(GetGlobalConfig(), "Video",
  108. "FPSType");
  109. LoadFPSCommon();
  110. LoadFPSInteger();
  111. LoadFPSFraction();
  112. LoadFPSNanoseconds();
  113. if (!fpsType)
  114. return;
  115. else if (strcmp(fpsType, "Common") == 0)
  116. window->fpsTypeList->SetSelection(0);
  117. else if (strcmp(fpsType, "Integer") == 0)
  118. window->fpsTypeList->SetSelection(1);
  119. else if (strcmp(fpsType, "Fraction") == 0)
  120. window->fpsTypeList->SetSelection(2);
  121. else if (strcmp(fpsType, "Nanoseconds") == 0)
  122. window->fpsTypeList->SetSelection(3);
  123. }
  124. void BasicVideoData::LoadFPSCommon()
  125. {
  126. const char *str = config_get_string(GetGlobalConfig(), "Video",
  127. "FPSCommon");
  128. int val = 3;
  129. if (strcmp(str, "10") == 0)
  130. val = 0;
  131. else if (strcmp(str, "20") == 0)
  132. val = 1;
  133. else if (strcmp(str, "29.97") == 0)
  134. val = 2;
  135. else if (strcmp(str, "30") == 0)
  136. val = 3;
  137. else if (strcmp(str, "48") == 0)
  138. val = 4;
  139. else if (strcmp(str, "59.94") == 0)
  140. val = 5;
  141. else if (strcmp(str, "60") == 0)
  142. val = 6;
  143. window->fpsCommonList->SetSelection(val);
  144. }
  145. void BasicVideoData::LoadFPSInteger()
  146. {
  147. window->fpsTypeList->SetSelection(1);
  148. int val = config_get_int(GetGlobalConfig(), "Video", "FPSInt");
  149. window->fpsIntegerScroller->SetValue(val);
  150. }
  151. void BasicVideoData::LoadFPSFraction()
  152. {
  153. window->fpsTypeList->SetSelection(2);
  154. int num = config_get_int(GetGlobalConfig(), "Video", "FPSNum");
  155. int den = config_get_int(GetGlobalConfig(), "Video", "FPSDen");
  156. window->fpsNumeratorScroller->SetValue(num);
  157. window->fpsDenominatorScroller->SetValue(den);
  158. }
  159. void BasicVideoData::LoadFPSNanoseconds()
  160. {
  161. window->fpsTypeList->SetSelection(3);
  162. int val = config_get_int(GetGlobalConfig(), "Video", "FPSNS");
  163. window->fpsNanosecondsScroller->SetValue(val);
  164. }
  165. /* some nice default output resolution vals */
  166. static const double vals[] =
  167. {
  168. 1.0,
  169. 1.25,
  170. (1.0/0.75),
  171. 1.5,
  172. (1.0/0.6),
  173. 1.75,
  174. 2.0,
  175. 2.25,
  176. 2.5,
  177. 2.75,
  178. 3.0
  179. };
  180. static const size_t numVals = sizeof(vals)/sizeof(double);
  181. void BasicVideoData::ResetScaleList(uint32_t cx, uint32_t cy)
  182. {
  183. window->outputResList->Clear();
  184. for (size_t i = 0; i < numVals; i++) {
  185. stringstream res;
  186. res << uint32_t(double(cx) / vals[i]);
  187. res << "x";
  188. res << uint32_t(double(cy) / vals[i]);
  189. window->outputResList->Append(res.str().c_str());
  190. }
  191. }
  192. BasicVideoData::BasicVideoData(OBSBasicSettings *window)
  193. : BasicSettingsData(window)
  194. {
  195. LoadResolutionData();
  196. LoadFPSData();
  197. /* load connectors after loading data to prevent them from triggering */
  198. connections.Add(window->baseResList, wxEVT_TEXT,
  199. wxCommandEventHandler(
  200. BasicVideoData::BaseResListChanged),
  201. NULL, this);
  202. connections.Add(window->outputResList, wxEVT_TEXT,
  203. wxCommandEventHandler(
  204. BasicVideoData::OutputResListChanged),
  205. NULL, this);
  206. window->videoChangedText->Hide();
  207. }
  208. void BasicVideoData::BaseResListChanged(wxCommandEvent &event)
  209. {
  210. uint32_t cx, cy;
  211. if (!ConvertTextRes(window->baseResList, cx, cy)) {
  212. window->videoChangedText->SetLabel(
  213. WXStr("Settings.Video.InvalidResolution"));
  214. window->videoChangedText->Show();
  215. return;
  216. }
  217. dataChanged = true;
  218. window->videoChangedText->SetLabel(WXStr("Settings.StreamRestart"));
  219. window->videoChangedText->Show();
  220. ResetScaleList(cx, cy);
  221. }
  222. void BasicVideoData::OutputResListChanged(wxCommandEvent &event)
  223. {
  224. uint32_t cx, cy;
  225. if (!ConvertTextRes(window->outputResList, cx, cy)) {
  226. window->videoChangedText->SetLabel(
  227. WXStr("Settings.Video.InvalidResolution"));
  228. window->videoChangedText->Show();
  229. return;
  230. }
  231. dataChanged = true;
  232. window->videoChangedText->SetLabel(WXStr("Settings.StreamRestart"));
  233. window->videoChangedText->Show();
  234. }
  235. void BasicVideoData::SaveFPSData()
  236. {
  237. int id = window->fpsTypeList->GetCurrentPage()->GetId();
  238. const char *type;
  239. switch (id) {
  240. case ID_FPSPANEL_COMMON: type = "Common"; break;
  241. case ID_FPSPANEL_INTEGER: type = "Integer"; break;
  242. case ID_FPSPANEL_FRACTION: type = "Fraction"; break;
  243. case ID_FPSPANEL_NANOSECONDS: type = "Nanoseconds"; break;
  244. }
  245. config_set_string(GetGlobalConfig(), "Video", "FPSType", type);
  246. SaveFPSCommon();
  247. SaveFPSInteger();
  248. SaveFPSFraction();
  249. SaveFPSNanoseconds();
  250. }
  251. void BasicVideoData::SaveFPSCommon()
  252. {
  253. int sel = window->fpsCommonList->GetSelection();
  254. wxString str = window->fpsCommonList->GetString(sel);
  255. config_set_string(GetGlobalConfig(), "Video", "FPSCommon", str.c_str());
  256. }
  257. void BasicVideoData::SaveFPSInteger()
  258. {
  259. int val = window->fpsIntegerScroller->GetValue();
  260. config_set_int(GetGlobalConfig(), "Video", "FPSInt", val);
  261. }
  262. void BasicVideoData::SaveFPSFraction()
  263. {
  264. int num = window->fpsNumeratorScroller->GetValue();
  265. int den = window->fpsDenominatorScroller->GetValue();
  266. config_set_int(GetGlobalConfig(), "Video", "FPSNum", num);
  267. config_set_int(GetGlobalConfig(), "Video", "FPSDen", den);
  268. }
  269. void BasicVideoData::SaveFPSNanoseconds()
  270. {
  271. int val = window->fpsNanosecondsScroller->GetValue();
  272. config_set_int(GetGlobalConfig(), "Video", "FPSNS", val);
  273. }
  274. void BasicVideoData::Apply()
  275. {
  276. uint32_t cx, cy;
  277. if (!ConvertTextRes(window->baseResList, cx, cy)) {
  278. config_set_uint(GetGlobalConfig(), "Video", "BaseCX", cx);
  279. config_set_uint(GetGlobalConfig(), "Video", "BaseCY", cy);
  280. }
  281. if (ConvertTextRes(window->outputResList, cx, cy)) {
  282. config_set_uint(GetGlobalConfig(), "Video", "OutputCX", cx);
  283. config_set_uint(GetGlobalConfig(), "Video", "OutputCY", cy);
  284. }
  285. SaveFPSData();
  286. }
  287. BasicSettingsData *CreateBasicVideoSettings(OBSBasicSettings *window)
  288. {
  289. return new BasicVideoData(window);
  290. }