window-basic-main.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. /******************************************************************************
  2. Copyright (C) 2013-2014 by Hugh Bailey <[email protected]>
  3. Copyright (C) 2014 by Zachary Lund <[email protected]>
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. ******************************************************************************/
  15. #include <obs.hpp>
  16. #include <QMessageBox>
  17. #include <QShowEvent>
  18. #include <QFileDialog>
  19. #include <util/util.hpp>
  20. #include <util/platform.h>
  21. #include "obs-app.hpp"
  22. #include "platform.hpp"
  23. #include "window-basic-settings.hpp"
  24. #include "window-namedialog.hpp"
  25. #include "window-basic-main.hpp"
  26. #include "qt-wrappers.hpp"
  27. #include "ui_OBSBasic.h"
  28. using namespace std;
  29. Q_DECLARE_METATYPE(OBSScene);
  30. Q_DECLARE_METATYPE(OBSSceneItem);
  31. OBSBasic::OBSBasic(QWidget *parent)
  32. : OBSMainWindow (parent),
  33. outputTest (NULL),
  34. sceneChanging (false),
  35. ui (new Ui::OBSBasic)
  36. {
  37. ui->setupUi(this);
  38. }
  39. bool OBSBasic::InitBasicConfigDefaults()
  40. {
  41. config_set_default_int(basicConfig, "Window", "PosX", -1);
  42. config_set_default_int(basicConfig, "Window", "PosY", -1);
  43. config_set_default_int(basicConfig, "Window", "SizeX", -1);
  44. config_set_default_int(basicConfig, "Window", "SizeY", -1);
  45. vector<MonitorInfo> monitors;
  46. GetMonitors(monitors);
  47. if (!monitors.size()) {
  48. OBSErrorBox(NULL, "There appears to be no monitors. Er, this "
  49. "technically shouldn't be possible.");
  50. return false;
  51. }
  52. uint32_t cx = monitors[0].cx;
  53. uint32_t cy = monitors[0].cy;
  54. config_set_default_uint (basicConfig, "Video", "BaseCX", cx);
  55. config_set_default_uint (basicConfig, "Video", "BaseCY", cy);
  56. cx = cx * 10 / 15;
  57. cy = cy * 10 / 15;
  58. config_set_default_uint (basicConfig, "Video", "OutputCX", cx);
  59. config_set_default_uint (basicConfig, "Video", "OutputCY", cy);
  60. config_set_default_uint (basicConfig, "Video", "FPSType", 0);
  61. config_set_default_string(basicConfig, "Video", "FPSCommon", "30");
  62. config_set_default_uint (basicConfig, "Video", "FPSInt", 30);
  63. config_set_default_uint (basicConfig, "Video", "FPSNum", 30);
  64. config_set_default_uint (basicConfig, "Video", "FPSDen", 1);
  65. config_set_default_uint (basicConfig, "Audio", "SampleRate", 44100);
  66. config_set_default_string(basicConfig, "Audio", "ChannelSetup",
  67. "Stereo");
  68. config_set_default_uint (basicConfig, "Audio", "BufferingTime", 1000);
  69. return true;
  70. }
  71. bool OBSBasic::InitBasicConfig()
  72. {
  73. BPtr<char> configPath(os_get_config_path("obs-studio/basic/basic.ini"));
  74. int errorcode = basicConfig.Open(configPath, CONFIG_OPEN_ALWAYS);
  75. if (errorcode != CONFIG_SUCCESS) {
  76. OBSErrorBox(NULL, "Failed to open basic.ini: %d", errorcode);
  77. return false;
  78. }
  79. return InitBasicConfigDefaults();
  80. }
  81. void OBSBasic::OBSInit()
  82. {
  83. /* make sure it's fully displayed before doing any initialization */
  84. show();
  85. App()->processEvents();
  86. if (!obs_startup())
  87. throw "Failed to initialize libobs";
  88. if (!InitBasicConfig())
  89. throw "Failed to load basic.ini";
  90. if (!ResetVideo())
  91. throw "Failed to initialize video";
  92. if (!ResetAudio())
  93. throw "Failed to initialize audio";
  94. signal_handler_connect(obs_signalhandler(), "source_add",
  95. OBSBasic::SourceAdded, this);
  96. signal_handler_connect(obs_signalhandler(), "source_remove",
  97. OBSBasic::SourceRemoved, this);
  98. signal_handler_connect(obs_signalhandler(), "channel_change",
  99. OBSBasic::ChannelChanged, this);
  100. /* TODO: this is a test, all modules will be searched for and loaded
  101. * automatically later */
  102. obs_load_module("test-input");
  103. obs_load_module("obs-ffmpeg");
  104. #ifdef __APPLE__
  105. obs_load_module("mac-capture");
  106. #elif _WIN32
  107. obs_load_module("win-wasapi");
  108. obs_load_module("win-capture");
  109. #endif
  110. }
  111. OBSBasic::~OBSBasic()
  112. {
  113. /* free the lists before shutting down to remove the scene/item
  114. * references */
  115. ui->sources->clear();
  116. ui->scenes->clear();
  117. obs_shutdown();
  118. }
  119. OBSScene OBSBasic::GetCurrentScene()
  120. {
  121. QListWidgetItem *item = ui->scenes->currentItem();
  122. return item ? item->data(Qt::UserRole).value<OBSScene>() : nullptr;
  123. }
  124. OBSSceneItem OBSBasic::GetCurrentSceneItem()
  125. {
  126. QListWidgetItem *item = ui->sources->currentItem();
  127. return item ? item->data(Qt::UserRole).value<OBSSceneItem>() : nullptr;
  128. }
  129. void OBSBasic::UpdateSources(OBSScene scene)
  130. {
  131. ui->sources->clear();
  132. obs_scene_enum_items(scene,
  133. [] (obs_scene_t scene, obs_sceneitem_t item, void *p)
  134. {
  135. OBSBasic *window = static_cast<OBSBasic*>(p);
  136. window->InsertSceneItem(item);
  137. UNUSED_PARAMETER(scene);
  138. return true;
  139. }, this);
  140. }
  141. void OBSBasic::InsertSceneItem(obs_sceneitem_t item)
  142. {
  143. obs_source_t source = obs_sceneitem_getsource(item);
  144. const char *name = obs_source_getname(source);
  145. QListWidgetItem *listItem = new QListWidgetItem(QT_UTF8(name));
  146. listItem->setData(Qt::UserRole,
  147. QVariant::fromValue(OBSSceneItem(item)));
  148. ui->sources->insertItem(0, listItem);
  149. }
  150. /* Qt callbacks for invokeMethod */
  151. void OBSBasic::AddScene(OBSSource source)
  152. {
  153. const char *name = obs_source_getname(source);
  154. obs_scene_t scene = obs_scene_fromsource(source);
  155. QListWidgetItem *item = new QListWidgetItem(QT_UTF8(name));
  156. item->setData(Qt::UserRole, QVariant::fromValue(OBSScene(scene)));
  157. ui->scenes->addItem(item);
  158. signal_handler_t handler = obs_source_signalhandler(source);
  159. signal_handler_connect(handler, "item_add",
  160. OBSBasic::SceneItemAdded, this);
  161. signal_handler_connect(handler, "item_remove",
  162. OBSBasic::SceneItemRemoved, this);
  163. }
  164. void OBSBasic::RemoveScene(OBSSource source)
  165. {
  166. const char *name = obs_source_getname(source);
  167. QListWidgetItem *sel = ui->scenes->currentItem();
  168. QList<QListWidgetItem*> items = ui->scenes->findItems(QT_UTF8(name),
  169. Qt::MatchExactly);
  170. if (sel != nullptr) {
  171. if (items.contains(sel))
  172. ui->sources->clear();
  173. delete sel;
  174. }
  175. }
  176. void OBSBasic::AddSceneItem(OBSSceneItem item)
  177. {
  178. obs_scene_t scene = obs_sceneitem_getscene(item);
  179. obs_source_t source = obs_sceneitem_getsource(item);
  180. if (GetCurrentScene() == scene)
  181. InsertSceneItem(item);
  182. sourceSceneRefs[source] = sourceSceneRefs[source] + 1;
  183. }
  184. void OBSBasic::RemoveSceneItem(OBSSceneItem item)
  185. {
  186. obs_scene_t scene = obs_sceneitem_getscene(item);
  187. if (GetCurrentScene() == scene) {
  188. for (int i = 0; i < ui->sources->count(); i++) {
  189. QListWidgetItem *listItem = ui->sources->item(i);
  190. QVariant userData = listItem->data(Qt::UserRole);
  191. if (userData.value<OBSSceneItem>() == item) {
  192. delete listItem;
  193. break;
  194. }
  195. }
  196. }
  197. obs_source_t source = obs_sceneitem_getsource(item);
  198. int scenes = sourceSceneRefs[source] - 1;
  199. if (scenes == 0) {
  200. obs_source_remove(source);
  201. sourceSceneRefs.erase(source);
  202. }
  203. }
  204. void OBSBasic::UpdateSceneSelection(OBSSource source)
  205. {
  206. if (source) {
  207. obs_source_type type;
  208. obs_source_gettype(source, &type, NULL);
  209. if (type != OBS_SOURCE_TYPE_SCENE)
  210. return;
  211. obs_scene_t scene = obs_scene_fromsource(source);
  212. const char *name = obs_source_getname(source);
  213. QList<QListWidgetItem*> items =
  214. ui->scenes->findItems(QT_UTF8(name), Qt::MatchExactly);
  215. if (items.count()) {
  216. sceneChanging = true;
  217. ui->scenes->setCurrentItem(items.first());
  218. sceneChanging = false;
  219. UpdateSources(scene);
  220. }
  221. }
  222. }
  223. /* OBS Callbacks */
  224. void OBSBasic::SceneItemAdded(void *data, calldata_t params)
  225. {
  226. OBSBasic *window = static_cast<OBSBasic*>(data);
  227. obs_sceneitem_t item = (obs_sceneitem_t)calldata_ptr(params, "item");
  228. QMetaObject::invokeMethod(window, "AddSceneItem",
  229. Q_ARG(OBSSceneItem, OBSSceneItem(item)));
  230. }
  231. void OBSBasic::SceneItemRemoved(void *data, calldata_t params)
  232. {
  233. OBSBasic *window = static_cast<OBSBasic*>(data);
  234. obs_sceneitem_t item = (obs_sceneitem_t)calldata_ptr(params, "item");
  235. QMetaObject::invokeMethod(window, "RemoveSceneItem",
  236. Q_ARG(OBSSceneItem, OBSSceneItem(item)));
  237. }
  238. void OBSBasic::SourceAdded(void *data, calldata_t params)
  239. {
  240. obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
  241. obs_source_type type;
  242. obs_source_gettype(source, &type, NULL);
  243. if (type == OBS_SOURCE_TYPE_SCENE)
  244. QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
  245. "AddScene",
  246. Q_ARG(OBSSource, OBSSource(source)));
  247. }
  248. void OBSBasic::SourceRemoved(void *data, calldata_t params)
  249. {
  250. obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
  251. obs_source_type type;
  252. obs_source_gettype(source, &type, NULL);
  253. if (type == OBS_SOURCE_TYPE_SCENE)
  254. QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
  255. "RemoveScene",
  256. Q_ARG(OBSSource, OBSSource(source)));
  257. }
  258. void OBSBasic::ChannelChanged(void *data, calldata_t params)
  259. {
  260. obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
  261. uint32_t channel = (uint32_t)calldata_int(params, "channel");
  262. if (channel == 0)
  263. QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
  264. "UpdateSceneSelection",
  265. Q_ARG(OBSSource, OBSSource(source)));
  266. }
  267. void OBSBasic::RenderMain(void *data, uint32_t cx, uint32_t cy)
  268. {
  269. OBSBasic *window = static_cast<OBSBasic*>(data);
  270. gs_matrix_push();
  271. gs_matrix_scale3f(window->previewScale, window->previewScale, 1.0f);
  272. gs_matrix_translate3f(-window->previewX, -window->previewY, 0.0f);
  273. obs_render_main_view();
  274. gs_matrix_pop();
  275. UNUSED_PARAMETER(cx);
  276. UNUSED_PARAMETER(cy);
  277. }
  278. /* Main class functions */
  279. bool OBSBasic::ResetVideo()
  280. {
  281. struct obs_video_info ovi;
  282. GetConfigFPS(ovi.fps_num, ovi.fps_den);
  283. ovi.graphics_module = App()->GetRenderModule();
  284. ovi.base_width = (uint32_t)config_get_uint(basicConfig,
  285. "Video", "BaseCX");
  286. ovi.base_height = (uint32_t)config_get_uint(basicConfig,
  287. "Video", "BaseCY");
  288. ovi.output_width = (uint32_t)config_get_uint(basicConfig,
  289. "Video", "OutputCX");
  290. ovi.output_height = (uint32_t)config_get_uint(basicConfig,
  291. "Video", "OutputCY");
  292. ovi.output_format = VIDEO_FORMAT_I420;
  293. ovi.adapter = 0;
  294. ovi.gpu_conversion = true;
  295. QTToGSWindow(ui->preview->winId(), ovi.window);
  296. //required to make opengl display stuff on osx(?)
  297. ResizePreview(ovi.base_width, ovi.base_height);
  298. QSize size = ui->preview->size();
  299. ovi.window_width = size.width();
  300. ovi.window_height = size.height();
  301. if (!obs_reset_video(&ovi))
  302. return false;
  303. obs_add_draw_callback(OBSBasic::RenderMain, this);
  304. return true;
  305. }
  306. bool OBSBasic::ResetAudio()
  307. {
  308. struct audio_output_info ai;
  309. ai.name = "Main Audio Track";
  310. ai.format = AUDIO_FORMAT_FLOAT;
  311. ai.samples_per_sec = config_get_uint(basicConfig, "Audio",
  312. "SampleRate");
  313. const char *channelSetupStr = config_get_string(basicConfig,
  314. "Audio", "ChannelSetup");
  315. if (strcmp(channelSetupStr, "Mono") == 0)
  316. ai.speakers = SPEAKERS_MONO;
  317. else
  318. ai.speakers = SPEAKERS_STEREO;
  319. ai.buffer_ms = config_get_uint(basicConfig, "Audio", "BufferingTime");
  320. return obs_reset_audio(&ai);
  321. }
  322. void OBSBasic::ResizePreview(uint32_t cx, uint32_t cy)
  323. {
  324. double targetAspect, baseAspect;
  325. QSize targetSize;
  326. int x, y;
  327. /* resize preview panel to fix to the top section of the window */
  328. targetSize = ui->preview->size();
  329. targetAspect = double(targetSize.width()) / double(targetSize.height());
  330. baseAspect = double(cx) / double(cy);
  331. if (targetAspect > baseAspect) {
  332. previewScale = float(targetSize.height()) / float(cy);
  333. cx = targetSize.height() * baseAspect;
  334. cy = targetSize.height();
  335. } else {
  336. previewScale = float(targetSize.width()) / float(cx);
  337. cx = targetSize.width();
  338. cy = targetSize.width() / baseAspect;
  339. }
  340. previewX = targetSize.width() /2 - cx/2;
  341. previewY = targetSize.height()/2 - cy/2;
  342. if (isVisible()) {
  343. if (resizeTimer)
  344. killTimer(resizeTimer);
  345. resizeTimer = startTimer(100);
  346. }
  347. }
  348. void OBSBasic::closeEvent(QCloseEvent *event)
  349. {
  350. /* TODO */
  351. UNUSED_PARAMETER(event);
  352. }
  353. void OBSBasic::changeEvent(QEvent *event)
  354. {
  355. /* TODO */
  356. UNUSED_PARAMETER(event);
  357. }
  358. void OBSBasic::resizeEvent(QResizeEvent *event)
  359. {
  360. struct obs_video_info ovi;
  361. if (obs_get_video_info(&ovi))
  362. ResizePreview(ovi.base_width, ovi.base_height);
  363. UNUSED_PARAMETER(event);
  364. }
  365. void OBSBasic::timerEvent(QTimerEvent *event)
  366. {
  367. if (event->timerId() == resizeTimer) {
  368. killTimer(resizeTimer);
  369. resizeTimer = 0;
  370. QSize size = ui->preview->size();
  371. obs_resize(size.width(), size.height());
  372. }
  373. }
  374. void OBSBasic::on_action_New_triggered()
  375. {
  376. /* TODO */
  377. }
  378. void OBSBasic::on_action_Open_triggered()
  379. {
  380. /* TODO */
  381. }
  382. void OBSBasic::on_action_Save_triggered()
  383. {
  384. /* TODO */
  385. }
  386. void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
  387. QListWidgetItem *prev)
  388. {
  389. obs_source_t source = NULL;
  390. if (sceneChanging)
  391. return;
  392. if (current) {
  393. obs_scene_t scene;
  394. scene = current->data(Qt::UserRole).value<OBSScene>();
  395. source = obs_scene_getsource(scene);
  396. }
  397. /* TODO: allow transitions */
  398. obs_set_output_source(0, source);
  399. UNUSED_PARAMETER(prev);
  400. }
  401. void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
  402. {
  403. /* TODO */
  404. UNUSED_PARAMETER(pos);
  405. }
  406. void OBSBasic::on_actionAddScene_triggered()
  407. {
  408. string name;
  409. bool accepted = NameDialog::AskForName(this,
  410. QTStr("MainWindow.AddSceneDlg.Title"),
  411. QTStr("MainWindow.AddSceneDlg.Text"),
  412. name);
  413. if (accepted) {
  414. obs_source_t source = obs_get_source_by_name(name.c_str());
  415. if (source) {
  416. QMessageBox::information(this,
  417. QTStr("MainWindow.NameExists.Title"),
  418. QTStr("MainWindow.NameExists.Text"));
  419. obs_source_release(source);
  420. on_actionAddScene_triggered();
  421. return;
  422. }
  423. obs_scene_t scene = obs_scene_create(name.c_str());
  424. source = obs_scene_getsource(scene);
  425. obs_add_source(source);
  426. obs_scene_release(scene);
  427. obs_set_output_source(0, source);
  428. }
  429. }
  430. void OBSBasic::on_actionRemoveScene_triggered()
  431. {
  432. QListWidgetItem *item = ui->scenes->currentItem();
  433. if (!item)
  434. return;
  435. QVariant userData = item->data(Qt::UserRole);
  436. obs_scene_t scene = userData.value<OBSScene>();
  437. obs_source_t source = obs_scene_getsource(scene);
  438. obs_source_remove(source);
  439. }
  440. void OBSBasic::on_actionSceneProperties_triggered()
  441. {
  442. /* TODO */
  443. }
  444. void OBSBasic::on_actionSceneUp_triggered()
  445. {
  446. /* TODO */
  447. }
  448. void OBSBasic::on_actionSceneDown_triggered()
  449. {
  450. /* TODO */
  451. }
  452. void OBSBasic::on_sources_currentItemChanged(QListWidgetItem *current,
  453. QListWidgetItem *prev)
  454. {
  455. /* TODO */
  456. UNUSED_PARAMETER(current);
  457. UNUSED_PARAMETER(prev);
  458. }
  459. void OBSBasic::on_sources_customContextMenuRequested(const QPoint &pos)
  460. {
  461. /* TODO */
  462. UNUSED_PARAMETER(pos);
  463. }
  464. void OBSBasic::AddSource(obs_scene_t scene, const char *id)
  465. {
  466. string name;
  467. bool success = false;
  468. while (!success) {
  469. bool accepted = NameDialog::AskForName(this,
  470. Str("MainWindow.AddSourceDlg.Title"),
  471. Str("MainWindow.AddSourceDlg.Text"),
  472. name);
  473. if (!accepted)
  474. break;
  475. obs_source_t source = obs_get_source_by_name(name.c_str());
  476. if (!source) {
  477. success = true;
  478. } else {
  479. QMessageBox::information(this,
  480. QTStr("MainWindow.NameExists.Title"),
  481. QTStr("MainWindow.NameExists.Text"));
  482. obs_source_release(source);
  483. }
  484. }
  485. if (success) {
  486. obs_source_t source = obs_source_create(OBS_SOURCE_TYPE_INPUT,
  487. id, name.c_str(), NULL);
  488. sourceSceneRefs[source] = 0;
  489. obs_add_source(source);
  490. obs_scene_add(scene, source);
  491. obs_source_release(source);
  492. }
  493. }
  494. void OBSBasic::AddSourcePopupMenu(const QPoint &pos)
  495. {
  496. OBSScene scene = GetCurrentScene();
  497. const char *type;
  498. bool foundValues = false;
  499. size_t idx = 0;
  500. if (!scene)
  501. return;
  502. QMenu popup;
  503. while (obs_enum_input_types(idx++, &type)) {
  504. const char *name = obs_source_getdisplayname(
  505. OBS_SOURCE_TYPE_INPUT,
  506. type, App()->GetLocale());
  507. QAction *popupItem = new QAction(QT_UTF8(name), this);
  508. popupItem->setData(QT_UTF8(type));
  509. popup.addAction(popupItem);
  510. foundValues = true;
  511. }
  512. if (foundValues) {
  513. QAction *ret = popup.exec(pos);
  514. if (ret)
  515. AddSource(scene, ret->data().toString().toUtf8());
  516. }
  517. }
  518. void OBSBasic::on_actionAddSource_triggered()
  519. {
  520. AddSourcePopupMenu(QCursor::pos());
  521. }
  522. void OBSBasic::on_actionRemoveSource_triggered()
  523. {
  524. OBSSceneItem item = GetCurrentSceneItem();
  525. if (item)
  526. obs_sceneitem_remove(item);
  527. }
  528. void OBSBasic::on_actionSourceProperties_triggered()
  529. {
  530. }
  531. void OBSBasic::on_actionSourceUp_triggered()
  532. {
  533. }
  534. void OBSBasic::on_actionSourceDown_triggered()
  535. {
  536. }
  537. void OBSBasic::on_recordButton_clicked()
  538. {
  539. if (outputTest) {
  540. obs_output_destroy(outputTest);
  541. outputTest = NULL;
  542. ui->recordButton->setText("Start Recording");
  543. } else {
  544. QString path = QFileDialog::getSaveFileName(this,
  545. "Please enter a file name", QString(),
  546. "MP4 Files (*.mp4)");
  547. if (path.isNull() || path.isEmpty())
  548. return;
  549. obs_data_t data = obs_data_create();
  550. obs_data_setstring(data, "filename", QT_TO_UTF8(path));
  551. outputTest = obs_output_create("ffmpeg_output", "test", data);
  552. obs_data_release(data);
  553. if (!obs_output_start(outputTest)) {
  554. obs_output_destroy(outputTest);
  555. outputTest = NULL;
  556. return;
  557. }
  558. ui->recordButton->setText("Stop Recording");
  559. }
  560. }
  561. void OBSBasic::on_settingsButton_clicked()
  562. {
  563. OBSBasicSettings settings(this);
  564. settings.exec();
  565. }
  566. void OBSBasic::GetFPSCommon(uint32_t &num, uint32_t &den) const
  567. {
  568. const char *val = config_get_string(basicConfig, "Video", "FPSCommon");
  569. if (strcmp(val, "10") == 0) {
  570. num = 10;
  571. den = 1;
  572. } else if (strcmp(val, "20") == 0) {
  573. num = 20;
  574. den = 1;
  575. } else if (strcmp(val, "25") == 0) {
  576. num = 25;
  577. den = 1;
  578. } else if (strcmp(val, "29.97") == 0) {
  579. num = 30000;
  580. den = 1001;
  581. } else if (strcmp(val, "48") == 0) {
  582. num = 48;
  583. den = 1;
  584. } else if (strcmp(val, "59.94") == 0) {
  585. num = 60000;
  586. den = 1001;
  587. } else if (strcmp(val, "60") == 0) {
  588. num = 60;
  589. den = 1;
  590. } else {
  591. num = 30;
  592. den = 1;
  593. }
  594. }
  595. void OBSBasic::GetFPSInteger(uint32_t &num, uint32_t &den) const
  596. {
  597. num = (uint32_t)config_get_uint(basicConfig, "Video", "FPSInt");
  598. den = 1;
  599. }
  600. void OBSBasic::GetFPSFraction(uint32_t &num, uint32_t &den) const
  601. {
  602. num = (uint32_t)config_get_uint(basicConfig, "Video", "FPSNum");
  603. den = (uint32_t)config_get_uint(basicConfig, "Video", "FPSDen");
  604. }
  605. void OBSBasic::GetFPSNanoseconds(uint32_t &num, uint32_t &den) const
  606. {
  607. num = 1000000000;
  608. den = (uint32_t)config_get_uint(basicConfig, "Video", "FPSNS");
  609. }
  610. void OBSBasic::GetConfigFPS(uint32_t &num, uint32_t &den) const
  611. {
  612. uint32_t type = config_get_uint(basicConfig, "Video", "FPSType");
  613. if (type == 1) //"Integer"
  614. GetFPSInteger(num, den);
  615. else if (type == 2) //"Fraction"
  616. GetFPSFraction(num, den);
  617. else if (false) //"Nanoseconds", currently not implemented
  618. GetFPSNanoseconds(num, den);
  619. else
  620. GetFPSCommon(num, den);
  621. }
  622. config_t OBSBasic::Config() const
  623. {
  624. return basicConfig;
  625. }