window-basic-main.cpp 18.1 KB
Newer Older
1
/******************************************************************************
2
    Copyright (C) 2013-2014 by Hugh Bailey <obs.jim@gmail.com>
3
    Copyright (C) 2014 by Zachary Lund <admin@computerquip.com>
4 5 6

    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
7
    the Free Software Foundation, either version 2 of the License, or
8 9 10
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13 14 15 16 17 18
    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, see <http://www.gnu.org/licenses/>.
******************************************************************************/

J
jp9000 已提交
19
#include <obs.hpp>
J
jp9000 已提交
20
#include <QMessageBox>
21
#include <QShowEvent>
J
jp9000 已提交
22
#include <QFileDialog>
23

24 25 26
#include <util/util.hpp>
#include <util/platform.h>

27
#include "obs-app.hpp"
28
#include "platform.hpp"
29
#include "window-basic-settings.hpp"
30
#include "window-namedialog.hpp"
J
jp9000 已提交
31 32
#include "window-basic-main.hpp"
#include "qt-wrappers.hpp"
33

J
jp9000 已提交
34
#include "ui_OBSBasic.h"
35

36
using namespace std;
J
jp9000 已提交
37

J
jp9000 已提交
38 39 40
Q_DECLARE_METATYPE(OBSScene);
Q_DECLARE_METATYPE(OBSSceneItem);

41 42
OBSBasic::OBSBasic(QWidget *parent)
	: OBSMainWindow (parent),
J
jp9000 已提交
43
	  outputTest    (NULL),
44
	  sceneChanging (false),
J
jp9000 已提交
45
	  ui            (new Ui::OBSBasic)
46 47 48 49
{
	ui->setupUi(this);
}

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
bool OBSBasic::InitBasicConfigDefaults()
{
	config_set_default_int(basicConfig, "Window", "PosX",  -1);
	config_set_default_int(basicConfig, "Window", "PosY",  -1);
	config_set_default_int(basicConfig, "Window", "SizeX", -1);
	config_set_default_int(basicConfig, "Window", "SizeY", -1);

	vector<MonitorInfo> monitors;
	GetMonitors(monitors);

	if (!monitors.size()) {
		OBSErrorBox(NULL, "There appears to be no monitors.  Er, this "
		                  "technically shouldn't be possible.");
		return false;
	}

	uint32_t cx = monitors[0].cx;
	uint32_t cy = monitors[0].cy;

	config_set_default_uint  (basicConfig, "Video", "BaseCX",   cx);
	config_set_default_uint  (basicConfig, "Video", "BaseCY",   cy);

	cx = cx * 10 / 15;
	cy = cy * 10 / 15;
	config_set_default_uint  (basicConfig, "Video", "OutputCX", cx);
	config_set_default_uint  (basicConfig, "Video", "OutputCY", cy);

	config_set_default_uint  (basicConfig, "Video", "FPSType", 0);
	config_set_default_string(basicConfig, "Video", "FPSCommon", "30");
	config_set_default_uint  (basicConfig, "Video", "FPSInt", 30);
	config_set_default_uint  (basicConfig, "Video", "FPSNum", 30);
	config_set_default_uint  (basicConfig, "Video", "FPSDen", 1);

	config_set_default_uint  (basicConfig, "Audio", "SampleRate", 44100);
	config_set_default_string(basicConfig, "Audio", "ChannelSetup",
			"Stereo");
	config_set_default_uint  (basicConfig, "Audio", "BufferingTime", 1000);

	return true;
}

bool OBSBasic::InitBasicConfig()
{
	BPtr<char> configPath(os_get_config_path("obs-studio/basic/basic.ini"));

	int errorcode = basicConfig.Open(configPath, CONFIG_OPEN_ALWAYS);
	if (errorcode != CONFIG_SUCCESS) {
		OBSErrorBox(NULL, "Failed to open basic.ini: %d", errorcode);
		return false;
	}

	return InitBasicConfigDefaults();
}

104 105 106 107 108 109 110 111
void OBSBasic::OBSInit()
{
	/* make sure it's fully displayed before doing any initialization */
	show();
	App()->processEvents();

	if (!obs_startup())
		throw "Failed to initialize libobs";
112 113
	if (!InitBasicConfig())
		throw "Failed to load basic.ini";
114 115 116
	if (!ResetVideo())
		throw "Failed to initialize video";
	if (!ResetAudio())
117 118
		throw "Failed to initialize audio";

119
	signal_handler_connect(obs_signalhandler(), "source_add",
120
			OBSBasic::SourceAdded, this);
121
	signal_handler_connect(obs_signalhandler(), "source_remove",
122
			OBSBasic::SourceRemoved, this);
123
	signal_handler_connect(obs_signalhandler(), "channel_change",
124 125
			OBSBasic::ChannelChanged, this);

J
jp9000 已提交
126 127
	/* TODO: this is a test, all modules will be searched for and loaded
	 * automatically later */
128
	obs_load_module("test-input");
129
	obs_load_module("obs-ffmpeg");
J
jp9000 已提交
130 131
#ifdef __APPLE__
	obs_load_module("mac-capture");
J
jp9000 已提交
132 133
#elif _WIN32
	obs_load_module("win-wasapi");
J
jp9000 已提交
134
	obs_load_module("win-capture");
J
jp9000 已提交
135
#endif
136

137
	/* HACK: fixes a qt bug with native widgets with native repaint */
138 139 140 141 142 143 144 145 146 147 148 149
	ui->previewContainer->repaint();
}

OBSBasic::~OBSBasic()
{
	/* free the lists before shutting down to remove the scene/item
	 * references */
	ui->sources->clear();
	ui->scenes->clear();
	obs_shutdown();
}

J
jp9000 已提交
150
OBSScene OBSBasic::GetCurrentScene()
151
{
J
jp9000 已提交
152
	QListWidgetItem *item = ui->scenes->currentItem();
J
jp9000 已提交
153
	return item ? item->data(Qt::UserRole).value<OBSScene>() : nullptr;
154 155
}

J
jp9000 已提交
156
OBSSceneItem OBSBasic::GetCurrentSceneItem()
J
jp9000 已提交
157 158
{
	QListWidgetItem *item = ui->sources->currentItem();
J
jp9000 已提交
159
	return item ? item->data(Qt::UserRole).value<OBSSceneItem>() : nullptr;
J
jp9000 已提交
160 161
}

162 163 164 165 166 167 168 169
void OBSBasic::UpdateSources(OBSScene scene)
{
	ui->sources->clear();

	obs_scene_enum_items(scene,
			[] (obs_scene_t scene, obs_sceneitem_t item, void *p)
			{
				OBSBasic *window = static_cast<OBSBasic*>(p);
170
				window->InsertSceneItem(item);
J
jp9000 已提交
171 172

				UNUSED_PARAMETER(scene);
173 174 175 176
				return true;
			}, this);
}

177 178 179 180 181 182 183 184 185 186 187 188
void OBSBasic::InsertSceneItem(obs_sceneitem_t item)
{
	obs_source_t source = obs_sceneitem_getsource(item);
	const char   *name  = obs_source_getname(source);

	QListWidgetItem *listItem = new QListWidgetItem(QT_UTF8(name));
	listItem->setData(Qt::UserRole,
			QVariant::fromValue(OBSSceneItem(item)));

	ui->sources->insertItem(0, listItem);
}

189 190 191
/* Qt callbacks for invokeMethod */

void OBSBasic::AddScene(OBSSource source)
192 193 194
{
	const char *name  = obs_source_getname(source);
	obs_scene_t scene = obs_scene_fromsource(source);
J
jp9000 已提交
195 196

	QListWidgetItem *item = new QListWidgetItem(QT_UTF8(name));
J
jp9000 已提交
197
	item->setData(Qt::UserRole, QVariant::fromValue(OBSScene(scene)));
J
jp9000 已提交
198
	ui->scenes->addItem(item);
199 200

	signal_handler_t handler = obs_source_signalhandler(source);
201
	signal_handler_connect(handler, "item_add",
J
jp9000 已提交
202
			OBSBasic::SceneItemAdded, this);
203
	signal_handler_connect(handler, "item_remove",
J
jp9000 已提交
204
			OBSBasic::SceneItemRemoved, this);
205 206
}

207
void OBSBasic::RemoveScene(OBSSource source)
J
jp9000 已提交
208 209 210
{
	const char *name = obs_source_getname(source);

J
jp9000 已提交
211 212 213
	QListWidgetItem *sel = ui->scenes->currentItem();
	QList<QListWidgetItem*> items = ui->scenes->findItems(QT_UTF8(name),
			Qt::MatchExactly);
J
jp9000 已提交
214

J
jp9000 已提交
215 216 217 218
	if (sel != nullptr) {
		if (items.contains(sel))
			ui->sources->clear();
		delete sel;
J
jp9000 已提交
219
	}
220 221
}

222
void OBSBasic::AddSceneItem(OBSSceneItem item)
223
{
J
jp9000 已提交
224
	obs_scene_t  scene  = obs_sceneitem_getscene(item);
225
	obs_source_t source = obs_sceneitem_getsource(item);
J
jp9000 已提交
226

227 228
	if (GetCurrentScene() == scene)
		InsertSceneItem(item);
J
jp9000 已提交
229 230

	sourceSceneRefs[source] = sourceSceneRefs[source] + 1;
231 232
}

233
void OBSBasic::RemoveSceneItem(OBSSceneItem item)
234
{
J
jp9000 已提交
235
	obs_scene_t scene = obs_sceneitem_getscene(item);
236

J
jp9000 已提交
237
	if (GetCurrentScene() == scene) {
B
BtbN 已提交
238
		for (int i = 0; i < ui->sources->count(); i++) {
J
jp9000 已提交
239 240
			QListWidgetItem *listItem = ui->sources->item(i);
			QVariant userData = listItem->data(Qt::UserRole);
J
jp9000 已提交
241

J
jp9000 已提交
242
			if (userData.value<OBSSceneItem>() == item) {
J
jp9000 已提交
243
				delete listItem;
J
jp9000 已提交
244 245
				break;
			}
246 247
		}
	}
J
jp9000 已提交
248 249 250 251 252 253 254 255

	obs_source_t source = obs_sceneitem_getsource(item);

	int scenes = sourceSceneRefs[source] - 1;
	if (scenes == 0) {
		obs_source_remove(source);
		sourceSceneRefs.erase(source);
	}
256 257
}

258
void OBSBasic::UpdateSceneSelection(OBSSource source)
259 260 261 262 263
{
	if (source) {
		obs_source_type type;
		obs_source_gettype(source, &type, NULL);

J
jp9000 已提交
264
		if (type != OBS_SOURCE_TYPE_SCENE)
J
jp9000 已提交
265
			return;
266

J
jp9000 已提交
267 268 269 270 271 272
		obs_scene_t scene = obs_scene_fromsource(source);
		const char *name = obs_source_getname(source);

		QList<QListWidgetItem*> items =
			ui->scenes->findItems(QT_UTF8(name), Qt::MatchExactly);

273 274 275 276 277
		if (items.count()) {
			sceneChanging = true;
			ui->scenes->setCurrentItem(items.first());
			sceneChanging = false;

J
jp9000 已提交
278
			UpdateSources(scene);
279
		}
J
jp9000 已提交
280
	}
281 282 283 284 285 286 287 288 289
}

/* OBS Callbacks */

void OBSBasic::SceneItemAdded(void *data, calldata_t params)
{
	OBSBasic *window = static_cast<OBSBasic*>(data);

	obs_sceneitem_t item = (obs_sceneitem_t)calldata_ptr(params, "item");
J
jp9000 已提交
290

291 292
	QMetaObject::invokeMethod(window, "AddSceneItem",
			Q_ARG(OBSSceneItem, OBSSceneItem(item)));
J
jp9000 已提交
293 294
}

295
void OBSBasic::SceneItemRemoved(void *data, calldata_t params)
296
{
297
	OBSBasic *window = static_cast<OBSBasic*>(data);
298

299 300
	obs_sceneitem_t item = (obs_sceneitem_t)calldata_ptr(params, "item");

301 302
	QMetaObject::invokeMethod(window, "RemoveSceneItem",
			Q_ARG(OBSSceneItem, OBSSceneItem(item)));
303 304 305 306 307
}

void OBSBasic::SourceAdded(void *data, calldata_t params)
{
	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
308 309 310 311

	obs_source_type type;
	obs_source_gettype(source, &type, NULL);

J
jp9000 已提交
312
	if (type == OBS_SOURCE_TYPE_SCENE)
313 314 315
		QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
				"AddScene",
				Q_ARG(OBSSource, OBSSource(source)));
316 317
}

J
jp9000 已提交
318
void OBSBasic::SourceRemoved(void *data, calldata_t params)
319
{
320
	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
321

J
jp9000 已提交
322 323 324
	obs_source_type type;
	obs_source_gettype(source, &type, NULL);

J
jp9000 已提交
325
	if (type == OBS_SOURCE_TYPE_SCENE)
326 327 328
		QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
				"RemoveScene",
				Q_ARG(OBSSource, OBSSource(source)));
329 330
}

331 332 333
void OBSBasic::ChannelChanged(void *data, calldata_t params)
{
	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
334
	uint32_t channel = (uint32_t)calldata_int(params, "channel");
335 336

	if (channel == 0)
337 338 339
		QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
				"UpdateSceneSelection",
				Q_ARG(OBSSource, OBSSource(source)));
340 341
}

342 343
void OBSBasic::RenderMain(void *data, uint32_t cx, uint32_t cy)
{
J
jp9000 已提交
344
	obs_render_main_view();
J
jp9000 已提交
345 346 347 348

	UNUSED_PARAMETER(data);
	UNUSED_PARAMETER(cx);
	UNUSED_PARAMETER(cy);
349 350
}

351 352
/* Main class functions */

353
bool OBSBasic::ResetVideo()
J
jp9000 已提交
354 355
{
	struct obs_video_info ovi;
J
jp9000 已提交
356

357
	GetConfigFPS(ovi.fps_num, ovi.fps_den);
J
jp9000 已提交
358 359

	ovi.graphics_module = App()->GetRenderModule();
360
	ovi.base_width     = (uint32_t)config_get_uint(basicConfig,
J
jp9000 已提交
361
			"Video", "BaseCX");
362
	ovi.base_height    = (uint32_t)config_get_uint(basicConfig,
J
jp9000 已提交
363
			"Video", "BaseCY");
364
	ovi.output_width   = (uint32_t)config_get_uint(basicConfig,
J
jp9000 已提交
365
			"Video", "OutputCX");
366
	ovi.output_height  = (uint32_t)config_get_uint(basicConfig,
J
jp9000 已提交
367
			"Video", "OutputCY");
J
jp9000 已提交
368 369 370
	ovi.output_format  = VIDEO_FORMAT_I420;
	ovi.adapter        = 0;
	ovi.gpu_conversion = true;
371

J
jp9000 已提交
372
	QTToGSWindow(ui->preview, ovi.window);
J
jp9000 已提交
373 374

	//required to make opengl display stuff on osx(?)
J
jp9000 已提交
375
	ResizePreview(ovi.base_width, ovi.base_height);
J
jp9000 已提交
376

J
jp9000 已提交
377 378 379
	QSize size = ui->preview->size();
	ovi.window_width  = size.width();
	ovi.window_height = size.height();
J
jp9000 已提交
380

381 382 383 384 385
	if (!obs_reset_video(&ovi))
		return false;

	obs_add_draw_callback(OBSBasic::RenderMain, this);
	return true;
J
jp9000 已提交
386
}
J
jp9000 已提交
387

388
bool OBSBasic::ResetAudio()
J
jp9000 已提交
389
{
J
jp9000 已提交
390
	struct audio_output_info ai;
391 392 393
	ai.name = "Main Audio Track";
	ai.format = AUDIO_FORMAT_FLOAT;

394
	ai.samples_per_sec = config_get_uint(basicConfig, "Audio",
395 396
			"SampleRate");

397
	const char *channelSetupStr = config_get_string(basicConfig,
398 399 400 401 402 403 404
			"Audio", "ChannelSetup");

	if (strcmp(channelSetupStr, "Mono") == 0)
		ai.speakers = SPEAKERS_MONO;
	else
		ai.speakers = SPEAKERS_STEREO;

405
	ai.buffer_ms = config_get_uint(basicConfig, "Audio", "BufferingTime");
J
jp9000 已提交
406 407

	return obs_reset_audio(&ai);
J
jp9000 已提交
408 409
}

J
jp9000 已提交
410
void OBSBasic::ResizePreview(uint32_t cx, uint32_t cy)
411
{
J
jp9000 已提交
412
	double targetAspect, baseAspect;
413 414
	QSize  targetSize;
	int x, y;
J
jp9000 已提交
415

416
	/* resize preview panel to fix to the top section of the window */
J
jp9000 已提交
417 418 419
	targetSize   = ui->previewContainer->size();
	targetAspect = double(targetSize.width()) / double(targetSize.height());
	baseAspect   = double(cx) / double(cy);
420

421 422 423 424 425 426 427 428 429 430
	if (targetAspect > baseAspect) {
		cx = targetSize.height() * baseAspect;
		cy = targetSize.height();
	} else {
		cx = targetSize.width();
		cy = targetSize.width() / baseAspect;
	}

	x = targetSize.width() /2 - cx/2;
	y = targetSize.height()/2 - cy/2;
431

432
	ui->preview->setGeometry(x, y, cx, cy);
J
jp9000 已提交
433

434 435
	if (isVisible())
		obs_resize(cx, cy);
J
jp9000 已提交
436 437
}

J
jp9000 已提交
438
void OBSBasic::closeEvent(QCloseEvent *event)
J
jp9000 已提交
439
{
J
jp9000 已提交
440 441
	/* TODO */
	UNUSED_PARAMETER(event);
442 443
}

J
jp9000 已提交
444
void OBSBasic::changeEvent(QEvent *event)
445
{
J
jp9000 已提交
446 447
	/* TODO */
	UNUSED_PARAMETER(event);
448 449
}

J
jp9000 已提交
450
void OBSBasic::resizeEvent(QResizeEvent *event)
451
{
J
jp9000 已提交
452 453 454 455
	struct obs_video_info ovi;

	if (obs_get_video_info(&ovi))
		ResizePreview(ovi.base_width, ovi.base_height);
J
jp9000 已提交
456 457

	UNUSED_PARAMETER(event);
458 459
}

J
jp9000 已提交
460
void OBSBasic::on_action_New_triggered()
461
{
J
jp9000 已提交
462
	/* TODO */
463 464
}

J
jp9000 已提交
465
void OBSBasic::on_action_Open_triggered()
466
{
J
jp9000 已提交
467
	/* TODO */
468 469
}

J
jp9000 已提交
470
void OBSBasic::on_action_Save_triggered()
471
{
J
jp9000 已提交
472
	/* TODO */
473 474
}

475 476
void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
		QListWidgetItem *prev)
477 478
{
	obs_source_t source = NULL;
J
jp9000 已提交
479

480 481 482 483
	if (sceneChanging)
		return;

	if (current) {
J
jp9000 已提交
484 485
		obs_scene_t scene;

486
		scene = current->data(Qt::UserRole).value<OBSScene>();
487 488 489
		source = obs_scene_getsource(scene);
	}

490
	/* TODO: allow transitions */
491
	obs_set_output_source(0, source);
492 493

	UNUSED_PARAMETER(prev);
494 495
}

J
jp9000 已提交
496
void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
497
{
J
jp9000 已提交
498 499
	/* TODO */
	UNUSED_PARAMETER(pos);
500 501
}

J
jp9000 已提交
502
void OBSBasic::on_actionAddScene_triggered()
503
{
504
	string name;
J
jp9000 已提交
505 506 507
	bool accepted = NameDialog::AskForName(this,
			QTStr("MainWindow.AddSceneDlg.Title"),
			QTStr("MainWindow.AddSceneDlg.Text"),
508 509
			name);

J
jp9000 已提交
510
	if (accepted) {
511 512
		obs_source_t source = obs_get_source_by_name(name.c_str());
		if (source) {
J
jp9000 已提交
513 514 515
			QMessageBox::information(this,
					QTStr("MainWindow.NameExists.Title"),
					QTStr("MainWindow.NameExists.Text"));
516 517

			obs_source_release(source);
J
jp9000 已提交
518
			on_actionAddScene_triggered();
519 520 521
			return;
		}

522
		obs_scene_t scene = obs_scene_create(name.c_str());
523 524
		source = obs_scene_getsource(scene);
		obs_add_source(source);
525
		obs_scene_release(scene);
526 527

		obs_set_output_source(0, source);
528
	}
529 530
}

J
jp9000 已提交
531
void OBSBasic::on_actionRemoveScene_triggered()
532
{
J
jp9000 已提交
533 534
	QListWidgetItem *item = ui->scenes->currentItem();
	if (!item)
J
jp9000 已提交
535 536
		return;

J
jp9000 已提交
537
	QVariant userData = item->data(Qt::UserRole);
J
jp9000 已提交
538
	obs_scene_t scene = userData.value<OBSScene>();
J
jp9000 已提交
539 540
	obs_source_t source = obs_scene_getsource(scene);
	obs_source_remove(source);
541 542
}

J
jp9000 已提交
543
void OBSBasic::on_actionSceneProperties_triggered()
544
{
J
jp9000 已提交
545
	/* TODO */
546 547
}

J
jp9000 已提交
548
void OBSBasic::on_actionSceneUp_triggered()
549
{
J
jp9000 已提交
550
	/* TODO */
551 552
}

J
jp9000 已提交
553
void OBSBasic::on_actionSceneDown_triggered()
554
{
J
jp9000 已提交
555
	/* TODO */
556 557
}

558 559
void OBSBasic::on_sources_currentItemChanged(QListWidgetItem *current,
		QListWidgetItem *prev)
560
{
J
jp9000 已提交
561
	/* TODO */
562 563
	UNUSED_PARAMETER(current);
	UNUSED_PARAMETER(prev);
564 565
}

J
jp9000 已提交
566
void OBSBasic::on_sources_customContextMenuRequested(const QPoint &pos)
567
{
J
jp9000 已提交
568 569
	/* TODO */
	UNUSED_PARAMETER(pos);
570 571
}

572 573 574 575 576 577
void OBSBasic::AddSource(obs_scene_t scene, const char *id)
{
	string name;

	bool success = false;
	while (!success) {
J
jp9000 已提交
578
		bool accepted = NameDialog::AskForName(this,
579 580 581 582
				Str("MainWindow.AddSourceDlg.Title"),
				Str("MainWindow.AddSourceDlg.Text"),
				name);

J
jp9000 已提交
583
		if (!accepted)
584 585
			break;

J
jp9000 已提交
586
		obs_source_t source = obs_get_source_by_name(name.c_str());
587 588 589
		if (!source) {
			success = true;
		} else {
J
jp9000 已提交
590 591 592
			QMessageBox::information(this,
					QTStr("MainWindow.NameExists.Title"),
					QTStr("MainWindow.NameExists.Text"));
593 594 595 596 597
			obs_source_release(source);
		}
	}

	if (success) {
J
jp9000 已提交
598 599
		obs_source_t source = obs_source_create(OBS_SOURCE_TYPE_INPUT,
				id, name.c_str(), NULL);
J
jp9000 已提交
600 601 602

		sourceSceneRefs[source] = 0;

603
		obs_add_source(source);
J
jp9000 已提交
604
		obs_scene_add(scene, source);
605 606 607 608
		obs_source_release(source);
	}
}

J
jp9000 已提交
609
void OBSBasic::AddSourcePopupMenu(const QPoint &pos)
610
{
611
	OBSScene scene = GetCurrentScene();
612
	const char *type;
J
jp9000 已提交
613 614
	bool foundValues = false;
	size_t idx = 0;
615

J
jp9000 已提交
616
	if (!scene)
617 618
		return;

J
jp9000 已提交
619 620
	QMenu popup;
	while (obs_enum_input_types(idx++, &type)) {
J
jp9000 已提交
621 622
		const char *name = obs_source_getdisplayname(
				OBS_SOURCE_TYPE_INPUT,
J
jp9000 已提交
623
				type, App()->GetLocale());
624

J
jp9000 已提交
625 626 627
		QAction *popupItem = new QAction(QT_UTF8(name), this);
		popupItem->setData(QT_UTF8(type));
		popup.addAction(popupItem);
628

J
jp9000 已提交
629
		foundValues = true;
630 631
	}

J
jp9000 已提交
632 633 634 635
	if (foundValues) {
		QAction *ret = popup.exec(pos);
		if (ret)
			AddSource(scene, ret->data().toString().toUtf8());
636 637 638
	}
}

J
jp9000 已提交
639
void OBSBasic::on_actionAddSource_triggered()
640
{
J
jp9000 已提交
641
	AddSourcePopupMenu(QCursor::pos());
642 643
}

J
jp9000 已提交
644
void OBSBasic::on_actionRemoveSource_triggered()
645
{
646
	OBSSceneItem item = GetCurrentSceneItem();
J
jp9000 已提交
647 648
	if (item)
		obs_sceneitem_remove(item);
649 650
}

J
jp9000 已提交
651
void OBSBasic::on_actionSourceProperties_triggered()
652 653 654
{
}

J
jp9000 已提交
655
void OBSBasic::on_actionSourceUp_triggered()
656 657
{
}
J
jp9000 已提交
658

J
jp9000 已提交
659
void OBSBasic::on_actionSourceDown_triggered()
660 661 662
{
}

J
jp9000 已提交
663 664 665 666 667 668 669 670 671
void OBSBasic::on_recordButton_clicked()
{
	if (outputTest) {
		obs_output_destroy(outputTest);
		outputTest = NULL;
		ui->recordButton->setText("Start Recording");
	} else {
		QString path = QFileDialog::getSaveFileName(this,
				"Please enter a file name", QString(),
672
				"MP4 Files (*.mp4)");
J
jp9000 已提交
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692

		if (path.isNull() || path.isEmpty())
			return;

		obs_data_t data = obs_data_create();
		obs_data_setstring(data, "filename", QT_TO_UTF8(path));

		outputTest = obs_output_create("ffmpeg_output", "test", data);
		obs_data_release(data);

		if (!obs_output_start(outputTest)) {
			obs_output_destroy(outputTest);
			outputTest = NULL;
			return;
		}

		ui->recordButton->setText("Stop Recording");
	}
}

J
jp9000 已提交
693
void OBSBasic::on_settingsButton_clicked()
J
jp9000 已提交
694
{
695 696
	OBSBasicSettings settings(this);
	settings.exec();
J
jp9000 已提交
697
}
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765

void OBSBasic::GetFPSCommon(uint32_t &num, uint32_t &den) const
{
	const char *val = config_get_string(basicConfig, "Video", "FPSCommon");

	if (strcmp(val, "10") == 0) {
		num = 10;
		den = 1;
	} else if (strcmp(val, "20") == 0) {
		num = 20;
		den = 1;
	} else if (strcmp(val, "25") == 0) {
		num = 25;
		den = 1;
	} else if (strcmp(val, "29.97") == 0) {
		num = 30000;
		den = 1001;
	} else if (strcmp(val, "48") == 0) {
		num = 48;
		den = 1;
	} else if (strcmp(val, "59.94") == 0) {
		num = 60000;
		den = 1001;
	} else if (strcmp(val, "60") == 0) {
		num = 60;
		den = 1;
	} else {
		num = 30;
		den = 1;
	}
}

void OBSBasic::GetFPSInteger(uint32_t &num, uint32_t &den) const
{
	num = (uint32_t)config_get_uint(basicConfig, "Video", "FPSInt");
	den = 1;
}

void OBSBasic::GetFPSFraction(uint32_t &num, uint32_t &den) const
{
	num = (uint32_t)config_get_uint(basicConfig, "Video", "FPSNum");
	den = (uint32_t)config_get_uint(basicConfig, "Video", "FPSDen");
}

void OBSBasic::GetFPSNanoseconds(uint32_t &num, uint32_t &den) const
{
	num = 1000000000;
	den = (uint32_t)config_get_uint(basicConfig, "Video", "FPSNS");
}

void OBSBasic::GetConfigFPS(uint32_t &num, uint32_t &den) const
{
	uint32_t type = config_get_uint(basicConfig, "Video", "FPSType");

	if (type == 1) //"Integer"
		GetFPSInteger(num, den);
	else if (type == 2) //"Fraction"
		GetFPSFraction(num, den);
	else if (false) //"Nanoseconds", currently not implemented
		GetFPSNanoseconds(num, den);
	else
		GetFPSCommon(num, den);
}

config_t OBSBasic::Config() const
{
	return basicConfig;
}