obs-studio/UI/window-basic-vcam-config.cpp

260 lines
5.9 KiB
C++

#include "window-basic-vcam-config.hpp"
#include "window-basic-main.hpp"
#include "qt-wrappers.hpp"
#include <util/util.hpp>
#include <util/platform.h>
enum class VCamOutputType {
Internal,
Scene,
Source,
};
enum class VCamInternalType {
Default,
Preview,
};
struct VCamConfig {
VCamOutputType type = VCamOutputType::Internal;
VCamInternalType internal = VCamInternalType::Default;
std::string scene;
std::string source;
};
static VCamConfig *vCamConfig = nullptr;
OBSBasicVCamConfig::OBSBasicVCamConfig(QWidget *parent)
: QDialog(parent), ui(new Ui::OBSBasicVCamConfig)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->setupUi(this);
auto type = (int)vCamConfig->type;
ui->outputType->setCurrentIndex(type);
OutputTypeChanged(type);
connect(ui->outputType,
static_cast<void (QComboBox::*)(int)>(
&QComboBox::currentIndexChanged),
this, &OBSBasicVCamConfig::OutputTypeChanged);
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
&OBSBasicVCamConfig::Save);
}
void OBSBasicVCamConfig::OutputTypeChanged(int type)
{
auto list = ui->outputSelection;
list->clear();
switch ((VCamOutputType)type) {
case VCamOutputType::Internal:
list->addItem(QTStr("Basic.VCam.InternalDefault"));
list->addItem(QTStr("Basic.VCam.InternalPreview"));
list->setCurrentIndex((int)vCamConfig->internal);
break;
case VCamOutputType::Scene: {
// Scenes in default order
BPtr<char *> scenes = obs_frontend_get_scene_names();
int idx = 0;
for (char **temp = scenes; *temp; temp++) {
list->addItem(*temp);
if (vCamConfig->scene.compare(*temp) == 0)
list->setCurrentIndex(list->count() - 1);
}
break;
}
case VCamOutputType::Source: {
// Sources in alphabetical order
std::vector<std::string> sources;
auto AddSource = [&](obs_source_t *source) {
auto name = obs_source_get_name(source);
auto flags = obs_source_get_output_flags(source);
if (!(obs_source_get_output_flags(source) &
OBS_SOURCE_VIDEO))
return;
sources.push_back(name);
};
using AddSource_t = decltype(AddSource);
obs_enum_sources(
[](void *data, obs_source_t *source) {
auto &AddSource =
*static_cast<AddSource_t *>(data);
if (!obs_source_removed(source))
AddSource(source);
return true;
},
static_cast<void *>(&AddSource));
// Sort and select current item
sort(sources.begin(), sources.end());
for (auto &&source : sources) {
list->addItem(source.c_str());
if (vCamConfig->source == source)
list->setCurrentIndex(list->count() - 1);
}
break;
}
}
}
void OBSBasicVCamConfig::Save()
{
auto type = (VCamOutputType)ui->outputType->currentIndex();
auto out = ui->outputSelection;
switch (type) {
case VCamOutputType::Internal:
vCamConfig->internal = (VCamInternalType)out->currentIndex();
break;
case VCamOutputType::Scene:
vCamConfig->scene = out->currentText().toStdString();
break;
case VCamOutputType::Source:
vCamConfig->source = out->currentText().toStdString();
break;
default:
// unknown value, don't save type
return;
}
vCamConfig->type = type;
// If already running just update the source
if (obs_frontend_virtualcam_active())
UpdateOutputSource();
}
void OBSBasicVCamConfig::SaveData(obs_data_t *data, bool saving)
{
if (saving) {
OBSDataAutoRelease obj = obs_data_create();
obs_data_set_int(obj, "type", (int)vCamConfig->type);
obs_data_set_int(obj, "internal", (int)vCamConfig->internal);
obs_data_set_string(obj, "scene", vCamConfig->scene.c_str());
obs_data_set_string(obj, "source", vCamConfig->source.c_str());
obs_data_set_obj(data, "virtual-camera", obj);
} else {
OBSDataAutoRelease obj =
obs_data_get_obj(data, "virtual-camera");
vCamConfig->type =
(VCamOutputType)obs_data_get_int(obj, "type");
vCamConfig->internal =
(VCamInternalType)obs_data_get_int(obj, "internal");
vCamConfig->scene = obs_data_get_string(obj, "scene");
vCamConfig->source = obs_data_get_string(obj, "source");
}
}
static void EventCallback(enum obs_frontend_event event, void *)
{
if (vCamConfig->type != VCamOutputType::Internal)
return;
// Update output source if the preview scene changes
// or if the default transition is changed
switch (event) {
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
if (vCamConfig->internal != VCamInternalType::Preview)
return;
break;
case OBS_FRONTEND_EVENT_TRANSITION_CHANGED:
if (vCamConfig->internal != VCamInternalType::Default)
return;
break;
default:
return;
}
OBSBasicVCamConfig::UpdateOutputSource();
}
static auto staticConfig = VCamConfig{};
void OBSBasicVCamConfig::Init()
{
if (vCamConfig)
return;
vCamConfig = &staticConfig;
obs_frontend_add_event_callback(EventCallback, nullptr);
}
static obs_view_t *view = nullptr;
static video_t *video = nullptr;
video_t *OBSBasicVCamConfig::StartVideo()
{
if (!view)
view = obs_view_create();
UpdateOutputSource();
if (!video)
video = obs_view_add(view);
return video;
}
void OBSBasicVCamConfig::StopVideo()
{
obs_view_remove(view);
obs_view_set_source(view, 0, nullptr);
video = nullptr;
}
void OBSBasicVCamConfig::DestroyView()
{
StopVideo();
obs_view_destroy(view);
view = nullptr;
}
void OBSBasicVCamConfig::UpdateOutputSource()
{
if (!view)
return;
obs_source_t *source = nullptr;
switch ((VCamOutputType)vCamConfig->type) {
case VCamOutputType::Internal:
switch (vCamConfig->internal) {
case VCamInternalType::Default:
source = obs_get_output_source(0);
break;
case VCamInternalType::Preview:
OBSSource s = OBSBasic::Get()->GetCurrentSceneSource();
obs_source_get_ref(s);
source = s;
break;
}
break;
case VCamOutputType::Scene:
source = obs_get_source_by_name(vCamConfig->scene.c_str());
break;
case VCamOutputType::Source:
source = obs_get_source_by_name(vCamConfig->source.c_str());
break;
}
auto current = obs_view_get_source(view, 0);
if (source != current)
obs_view_set_source(view, 0, source);
obs_source_release(source);
obs_source_release(current);
}