mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 23:34:08 +00:00
UI: Refactor Virtual Camera source selector dialog
This commit is contained in:
parent
dc5813c947
commit
501a3e926d
|
@ -259,6 +259,7 @@ target_sources(
|
||||||
window-basic-transform.cpp
|
window-basic-transform.cpp
|
||||||
window-basic-transform.hpp
|
window-basic-transform.hpp
|
||||||
window-basic-preview.hpp
|
window-basic-preview.hpp
|
||||||
|
window-basic-vcam.hpp
|
||||||
window-basic-vcam-config.cpp
|
window-basic-vcam-config.cpp
|
||||||
window-basic-vcam-config.hpp
|
window-basic-vcam-config.hpp
|
||||||
window-dock.cpp
|
window-dock.cpp
|
||||||
|
|
|
@ -181,7 +181,7 @@ static void OBSStopVirtualCam(void *data, calldata_t *params)
|
||||||
Q_ARG(int, code));
|
Q_ARG(int, code));
|
||||||
|
|
||||||
obs_output_set_media(output->virtualCam, nullptr, nullptr);
|
obs_output_set_media(output->virtualCam, nullptr, nullptr);
|
||||||
OBSBasicVCamConfig::StopVideo();
|
output->DestroyVirtualCamView();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
@ -229,23 +229,30 @@ inline BasicOutputHandler::BasicOutputHandler(OBSBasic *main_) : main(main_)
|
||||||
|
|
||||||
bool BasicOutputHandler::StartVirtualCam()
|
bool BasicOutputHandler::StartVirtualCam()
|
||||||
{
|
{
|
||||||
if (main->vcamEnabled) {
|
if (!main->vcamEnabled)
|
||||||
video_t *video = OBSBasicVCamConfig::StartVideo();
|
|
||||||
if (!video)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
obs_output_set_media(virtualCam, video, obs_get_audio());
|
if (!virtualCamView)
|
||||||
|
virtualCamView = obs_view_create();
|
||||||
|
|
||||||
|
UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
|
if (!virtualCamVideo) {
|
||||||
|
virtualCamVideo = obs_view_add(virtualCamView);
|
||||||
|
|
||||||
|
if (!virtualCamVideo)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_output_set_media(virtualCam, virtualCamVideo, obs_get_audio());
|
||||||
if (!Active())
|
if (!Active())
|
||||||
SetupOutputs();
|
SetupOutputs();
|
||||||
|
|
||||||
bool success = obs_output_start(virtualCam);
|
bool success = obs_output_start(virtualCam);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
OBSBasicVCamConfig::StopVideo();
|
DestroyVirtualCamView();
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasicOutputHandler::StopVirtualCam()
|
void BasicOutputHandler::StopVirtualCam()
|
||||||
|
@ -263,6 +270,85 @@ bool BasicOutputHandler::VirtualCamActive() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BasicOutputHandler::UpdateVirtualCamOutputSource()
|
||||||
|
{
|
||||||
|
if (!main->vcamEnabled || !virtualCamView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OBSSourceAutoRelease source;
|
||||||
|
|
||||||
|
switch (main->vcamConfig.type) {
|
||||||
|
case VCamOutputType::InternalOutput:
|
||||||
|
switch (main->vcamConfig.internal) {
|
||||||
|
case VCamInternalType::Default:
|
||||||
|
source = obs_get_output_source(0);
|
||||||
|
break;
|
||||||
|
case VCamInternalType::Preview:
|
||||||
|
OBSSource s = main->GetCurrentSceneSource();
|
||||||
|
obs_source_get_ref(s);
|
||||||
|
source = s.Get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VCamOutputType::SceneOutput:
|
||||||
|
source = obs_get_source_by_name(main->vcamConfig.scene.c_str());
|
||||||
|
break;
|
||||||
|
case VCamOutputType::SourceOutput:
|
||||||
|
OBSSource s =
|
||||||
|
obs_get_source_by_name(main->vcamConfig.source.c_str());
|
||||||
|
|
||||||
|
if (!vCamSourceScene)
|
||||||
|
vCamSourceScene =
|
||||||
|
obs_scene_create_private("vcam_source");
|
||||||
|
source = obs_source_get_ref(
|
||||||
|
obs_scene_get_source(vCamSourceScene));
|
||||||
|
|
||||||
|
if (vCamSourceSceneItem &&
|
||||||
|
(obs_sceneitem_get_source(vCamSourceSceneItem) != s)) {
|
||||||
|
obs_sceneitem_remove(vCamSourceSceneItem);
|
||||||
|
vCamSourceSceneItem = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vCamSourceSceneItem) {
|
||||||
|
vCamSourceSceneItem = obs_scene_add(vCamSourceScene, s);
|
||||||
|
obs_source_release(s);
|
||||||
|
|
||||||
|
obs_sceneitem_set_bounds_type(vCamSourceSceneItem,
|
||||||
|
OBS_BOUNDS_SCALE_INNER);
|
||||||
|
obs_sceneitem_set_bounds_alignment(vCamSourceSceneItem,
|
||||||
|
OBS_ALIGN_CENTER);
|
||||||
|
|
||||||
|
const struct vec2 size = {
|
||||||
|
(float)obs_source_get_width(source),
|
||||||
|
(float)obs_source_get_height(source),
|
||||||
|
};
|
||||||
|
obs_sceneitem_set_bounds(vCamSourceSceneItem, &size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSSourceAutoRelease current = obs_view_get_source(virtualCamView, 0);
|
||||||
|
if (source != current)
|
||||||
|
obs_view_set_source(virtualCamView, 0, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BasicOutputHandler::DestroyVirtualCamView()
|
||||||
|
{
|
||||||
|
obs_view_remove(virtualCamView);
|
||||||
|
obs_view_set_source(virtualCamView, 0, nullptr);
|
||||||
|
virtualCamVideo = nullptr;
|
||||||
|
|
||||||
|
obs_view_destroy(virtualCamView);
|
||||||
|
virtualCamView = nullptr;
|
||||||
|
|
||||||
|
if (!vCamSourceScene)
|
||||||
|
return;
|
||||||
|
|
||||||
|
obs_scene_release(vCamSourceScene);
|
||||||
|
vCamSourceScene = nullptr;
|
||||||
|
vCamSourceSceneItem = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
struct SimpleOutput : BasicOutputHandler {
|
struct SimpleOutput : BasicOutputHandler {
|
||||||
|
|
|
@ -16,6 +16,11 @@ struct BasicOutputHandler {
|
||||||
bool virtualCamActive = false;
|
bool virtualCamActive = false;
|
||||||
OBSBasic *main;
|
OBSBasic *main;
|
||||||
|
|
||||||
|
obs_view_t *virtualCamView = nullptr;
|
||||||
|
video_t *virtualCamVideo = nullptr;
|
||||||
|
obs_scene_t *vCamSourceScene = nullptr;
|
||||||
|
obs_sceneitem_t *vCamSourceSceneItem = nullptr;
|
||||||
|
|
||||||
std::string outputType;
|
std::string outputType;
|
||||||
std::string lastError;
|
std::string lastError;
|
||||||
|
|
||||||
|
@ -57,6 +62,9 @@ struct BasicOutputHandler {
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
virtual void SetupOutputs() = 0;
|
virtual void SetupOutputs() = 0;
|
||||||
|
|
||||||
|
virtual void UpdateVirtualCamOutputSource();
|
||||||
|
virtual void DestroyVirtualCamView();
|
||||||
|
|
||||||
inline bool Active() const
|
inline bool Active() const
|
||||||
{
|
{
|
||||||
return streamingActive || recordingActive || delayActive ||
|
return streamingActive || recordingActive || delayActive ||
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <util/dstr.hpp>
|
#include <util/dstr.hpp>
|
||||||
#include "window-basic-main.hpp"
|
#include "window-basic-main.hpp"
|
||||||
|
#include "window-basic-main-outputs.hpp"
|
||||||
#include "window-basic-vcam-config.hpp"
|
#include "window-basic-vcam-config.hpp"
|
||||||
#include "display-helpers.hpp"
|
#include "display-helpers.hpp"
|
||||||
#include "window-namedialog.hpp"
|
#include "window-namedialog.hpp"
|
||||||
|
@ -286,7 +287,8 @@ void OBSBasic::OverrideTransition(OBSSource transition)
|
||||||
obs_transition_swap_end(transition, oldTransition);
|
obs_transition_swap_end(transition, oldTransition);
|
||||||
|
|
||||||
// Transition overrides don't raise an event so we need to call update directly
|
// Transition overrides don't raise an event so we need to call update directly
|
||||||
OBSBasicVCamConfig::UpdateOutputSource();
|
if (vcamEnabled)
|
||||||
|
outputHandler->UpdateVirtualCamOutputSource();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,6 +430,9 @@ void OBSBasic::SetTransition(OBSSource transition)
|
||||||
ui->transitionRemove->setEnabled(configurable);
|
ui->transitionRemove->setEnabled(configurable);
|
||||||
ui->transitionProps->setEnabled(configurable);
|
ui->transitionProps->setEnabled(configurable);
|
||||||
|
|
||||||
|
if (vcamEnabled && vcamConfig.internal == VCamInternalType::Default)
|
||||||
|
outputHandler->UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
if (api)
|
if (api)
|
||||||
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_CHANGED);
|
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_CHANGED);
|
||||||
}
|
}
|
||||||
|
@ -695,6 +700,13 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force)
|
||||||
currentScene = itemScene.Get();
|
currentScene = itemScene.Get();
|
||||||
ui->scenes->setCurrentItem(item);
|
ui->scenes->setCurrentItem(item);
|
||||||
ui->scenes->blockSignals(false);
|
ui->scenes->blockSignals(false);
|
||||||
|
|
||||||
|
if (vcamEnabled &&
|
||||||
|
vcamConfig.internal ==
|
||||||
|
VCamInternalType::Preview)
|
||||||
|
outputHandler
|
||||||
|
->UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
if (api)
|
if (api)
|
||||||
api->on_event(
|
api->on_event(
|
||||||
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||||
|
|
|
@ -763,8 +763,27 @@ void OBSBasic::Save(const char *file)
|
||||||
obs_data_set_double(saveData, "scaling_off_y",
|
obs_data_set_double(saveData, "scaling_off_y",
|
||||||
ui->preview->GetScrollY());
|
ui->preview->GetScrollY());
|
||||||
|
|
||||||
if (vcamEnabled)
|
if (vcamEnabled) {
|
||||||
OBSBasicVCamConfig::SaveData(saveData, true);
|
OBSDataAutoRelease obj = obs_data_create();
|
||||||
|
|
||||||
|
obs_data_set_int(obj, "type", (int)vcamConfig.type);
|
||||||
|
switch (vcamConfig.type) {
|
||||||
|
case VCamOutputType::InternalOutput:
|
||||||
|
obs_data_set_int(obj, "internal",
|
||||||
|
(int)vcamConfig.internal);
|
||||||
|
break;
|
||||||
|
case VCamOutputType::SceneOutput:
|
||||||
|
obs_data_set_string(obj, "scene",
|
||||||
|
vcamConfig.scene.c_str());
|
||||||
|
break;
|
||||||
|
case VCamOutputType::SourceOutput:
|
||||||
|
obs_data_set_string(obj, "source",
|
||||||
|
vcamConfig.source.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_set_obj(saveData, "virtual-camera", obj);
|
||||||
|
}
|
||||||
|
|
||||||
if (api) {
|
if (api) {
|
||||||
OBSDataAutoRelease moduleObj = obs_data_create();
|
OBSDataAutoRelease moduleObj = obs_data_create();
|
||||||
|
@ -1178,8 +1197,16 @@ retryScene:
|
||||||
ui->preview->SetFixedScaling(fixedScaling);
|
ui->preview->SetFixedScaling(fixedScaling);
|
||||||
emit ui->preview->DisplayResized();
|
emit ui->preview->DisplayResized();
|
||||||
|
|
||||||
if (vcamEnabled)
|
if (vcamEnabled) {
|
||||||
OBSBasicVCamConfig::SaveData(data, false);
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------------- */
|
/* ---------------------- */
|
||||||
|
|
||||||
|
@ -1225,6 +1252,9 @@ retryScene:
|
||||||
|
|
||||||
disableSaving--;
|
disableSaving--;
|
||||||
|
|
||||||
|
if (vcamEnabled && vcamConfig.internal == VCamInternalType::Preview)
|
||||||
|
outputHandler->UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
if (api) {
|
if (api) {
|
||||||
api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||||
|
@ -1696,8 +1726,6 @@ void OBSBasic::ReplayBufferClicked()
|
||||||
|
|
||||||
void OBSBasic::AddVCamButton()
|
void OBSBasic::AddVCamButton()
|
||||||
{
|
{
|
||||||
OBSBasicVCamConfig::Init();
|
|
||||||
|
|
||||||
vcamButton = new ControlsSplitButton(
|
vcamButton = new ControlsSplitButton(
|
||||||
QTStr("Basic.Main.StartVirtualCam"), "vcamButton",
|
QTStr("Basic.Main.StartVirtualCam"), "vcamButton",
|
||||||
&OBSBasic::VCamButtonClicked);
|
&OBSBasic::VCamButtonClicked);
|
||||||
|
@ -2752,8 +2780,6 @@ OBSBasic::~OBSBasic()
|
||||||
delete cef;
|
delete cef;
|
||||||
cef = nullptr;
|
cef = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OBSBasicVCamConfig::DestroyView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::SaveProjectNow()
|
void OBSBasic::SaveProjectNow()
|
||||||
|
@ -5098,6 +5124,9 @@ void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
|
||||||
|
|
||||||
SetCurrentScene(source);
|
SetCurrentScene(source);
|
||||||
|
|
||||||
|
if (vcamEnabled && vcamConfig.internal == VCamInternalType::Preview)
|
||||||
|
outputHandler->UpdateVirtualCamOutputSource();
|
||||||
|
|
||||||
if (api)
|
if (api)
|
||||||
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
|
||||||
|
|
||||||
|
@ -7855,8 +7884,19 @@ void OBSBasic::VCamButtonClicked()
|
||||||
|
|
||||||
void OBSBasic::VCamConfigButtonClicked()
|
void OBSBasic::VCamConfigButtonClicked()
|
||||||
{
|
{
|
||||||
OBSBasicVCamConfig config(this);
|
OBSBasicVCamConfig dialog(vcamConfig, this);
|
||||||
config.exec();
|
|
||||||
|
connect(&dialog, &OBSBasicVCamConfig::Accepted, this,
|
||||||
|
&OBSBasic::UpdateVirtualCamConfig);
|
||||||
|
|
||||||
|
dialog.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::UpdateVirtualCamConfig(const VCamConfig &config)
|
||||||
|
{
|
||||||
|
vcamConfig = config;
|
||||||
|
|
||||||
|
outputHandler->UpdateVirtualCamOutputSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_settingsButton_clicked()
|
void OBSBasic::on_settingsButton_clicked()
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "window-main.hpp"
|
#include "window-main.hpp"
|
||||||
#include "window-basic-interaction.hpp"
|
#include "window-basic-interaction.hpp"
|
||||||
|
#include "window-basic-vcam.hpp"
|
||||||
#include "window-basic-properties.hpp"
|
#include "window-basic-properties.hpp"
|
||||||
#include "window-basic-transform.hpp"
|
#include "window-basic-transform.hpp"
|
||||||
#include "window-basic-adv-audio.hpp"
|
#include "window-basic-adv-audio.hpp"
|
||||||
|
@ -51,6 +52,7 @@ class QMessageBox;
|
||||||
class QListWidgetItem;
|
class QListWidgetItem;
|
||||||
class VolControl;
|
class VolControl;
|
||||||
class OBSBasicStats;
|
class OBSBasicStats;
|
||||||
|
class OBSBasicVCamConfig;
|
||||||
|
|
||||||
#include "ui_OBSBasic.h"
|
#include "ui_OBSBasic.h"
|
||||||
#include "ui_ColorSelect.h"
|
#include "ui_ColorSelect.h"
|
||||||
|
@ -309,6 +311,7 @@ private:
|
||||||
|
|
||||||
QPointer<ControlsSplitButton> vcamButton;
|
QPointer<ControlsSplitButton> vcamButton;
|
||||||
bool vcamEnabled = false;
|
bool vcamEnabled = false;
|
||||||
|
VCamConfig vcamConfig;
|
||||||
|
|
||||||
QScopedPointer<QSystemTrayIcon> trayIcon;
|
QScopedPointer<QSystemTrayIcon> trayIcon;
|
||||||
QPointer<QAction> sysTrayStream;
|
QPointer<QAction> sysTrayStream;
|
||||||
|
@ -819,6 +822,8 @@ private slots:
|
||||||
void LockVolumeControl(bool lock);
|
void LockVolumeControl(bool lock);
|
||||||
void ResetProxyStyleSliders();
|
void ResetProxyStyleSliders();
|
||||||
|
|
||||||
|
void UpdateVirtualCamConfig(const VCamConfig &config);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* OBS Callbacks */
|
/* OBS Callbacks */
|
||||||
static void SceneReordered(void *data, calldata_t *params);
|
static void SceneReordered(void *data, calldata_t *params);
|
||||||
|
|
|
@ -5,43 +5,21 @@
|
||||||
#include <util/util.hpp>
|
#include <util/util.hpp>
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
|
|
||||||
enum class VCamOutputType {
|
OBSBasicVCamConfig::OBSBasicVCamConfig(const VCamConfig &_config,
|
||||||
Internal,
|
QWidget *parent)
|
||||||
Scene,
|
: config(_config), QDialog(parent), ui(new Ui::OBSBasicVCamConfig)
|
||||||
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);
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
auto type = (int)vCamConfig->type;
|
ui->outputType->setCurrentIndex(config.type);
|
||||||
ui->outputType->setCurrentIndex(type);
|
OutputTypeChanged(config.type);
|
||||||
OutputTypeChanged(type);
|
connect(ui->outputType, SIGNAL(currentIndexChanged(int)), this,
|
||||||
connect(ui->outputType,
|
SLOT(OutputTypeChanged(int)));
|
||||||
static_cast<void (QComboBox::*)(int)>(
|
|
||||||
&QComboBox::currentIndexChanged),
|
|
||||||
this, &OBSBasicVCamConfig::OutputTypeChanged);
|
|
||||||
|
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
|
||||||
&OBSBasicVCamConfig::Save);
|
&OBSBasicVCamConfig::UpdateConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasicVCamConfig::OutputTypeChanged(int type)
|
void OBSBasicVCamConfig::OutputTypeChanged(int type)
|
||||||
|
@ -50,25 +28,25 @@ void OBSBasicVCamConfig::OutputTypeChanged(int type)
|
||||||
list->clear();
|
list->clear();
|
||||||
|
|
||||||
switch ((VCamOutputType)type) {
|
switch ((VCamOutputType)type) {
|
||||||
case VCamOutputType::Internal:
|
case VCamOutputType::InternalOutput:
|
||||||
list->addItem(QTStr("Basic.VCam.InternalDefault"));
|
list->addItem(QTStr("Basic.VCam.InternalDefault"));
|
||||||
list->addItem(QTStr("Basic.VCam.InternalPreview"));
|
list->addItem(QTStr("Basic.VCam.InternalPreview"));
|
||||||
list->setCurrentIndex((int)vCamConfig->internal);
|
list->setCurrentIndex(config.internal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VCamOutputType::Scene: {
|
case VCamOutputType::SceneOutput: {
|
||||||
// Scenes in default order
|
// Scenes in default order
|
||||||
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
||||||
for (char **temp = scenes; *temp; temp++) {
|
for (char **temp = scenes; *temp; temp++) {
|
||||||
list->addItem(*temp);
|
list->addItem(*temp);
|
||||||
|
|
||||||
if (vCamConfig->scene.compare(*temp) == 0)
|
if (config.scene.compare(*temp) == 0)
|
||||||
list->setCurrentIndex(list->count() - 1);
|
list->setCurrentIndex(list->count() - 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case VCamOutputType::Source: {
|
case VCamOutputType::SourceOutput: {
|
||||||
// Sources in alphabetical order
|
// Sources in alphabetical order
|
||||||
std::vector<std::string> sources;
|
std::vector<std::string> sources;
|
||||||
auto AddSource = [&](obs_source_t *source) {
|
auto AddSource = [&](obs_source_t *source) {
|
||||||
|
@ -97,7 +75,7 @@ void OBSBasicVCamConfig::OutputTypeChanged(int type)
|
||||||
for (auto &&source : sources) {
|
for (auto &&source : sources) {
|
||||||
list->addItem(source.c_str());
|
list->addItem(source.c_str());
|
||||||
|
|
||||||
if (vCamConfig->source == source)
|
if (config.source == source)
|
||||||
list->setCurrentIndex(list->count() - 1);
|
list->setCurrentIndex(list->count() - 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -105,193 +83,27 @@ void OBSBasicVCamConfig::OutputTypeChanged(int type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasicVCamConfig::Save()
|
void OBSBasicVCamConfig::UpdateConfig()
|
||||||
{
|
{
|
||||||
auto type = (VCamOutputType)ui->outputType->currentIndex();
|
VCamOutputType type = (VCamOutputType)ui->outputType->currentIndex();
|
||||||
auto out = ui->outputSelection;
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VCamOutputType::Internal:
|
case VCamOutputType::InternalOutput:
|
||||||
vCamConfig->internal = (VCamInternalType)out->currentIndex();
|
config.internal =
|
||||||
|
(VCamInternalType)ui->outputSelection->currentIndex();
|
||||||
break;
|
break;
|
||||||
case VCamOutputType::Scene:
|
case VCamOutputType::SceneOutput:
|
||||||
vCamConfig->scene = out->currentText().toStdString();
|
config.scene = ui->outputSelection->currentText().toStdString();
|
||||||
break;
|
break;
|
||||||
case VCamOutputType::Source:
|
case VCamOutputType::SourceOutput:
|
||||||
vCamConfig->source = out->currentText().toStdString();
|
config.source =
|
||||||
|
ui->outputSelection->currentText().toStdString();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// unknown value, don't save type
|
// unknown value, don't save type
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vCamConfig->type = type;
|
config.type = type;
|
||||||
|
|
||||||
// If already running just update the source
|
emit Accepted(config);
|
||||||
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;
|
|
||||||
|
|
||||||
static obs_scene_t *sourceScene = nullptr;
|
|
||||||
static obs_sceneitem_t *sourceSceneItem = 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;
|
|
||||||
|
|
||||||
if (sourceScene) {
|
|
||||||
obs_scene_release(sourceScene);
|
|
||||||
sourceScene = nullptr;
|
|
||||||
sourceSceneItem = 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:
|
|
||||||
auto rawSource =
|
|
||||||
obs_get_source_by_name(vCamConfig->source.c_str());
|
|
||||||
if (!rawSource)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Use a scene transform to fit the source size to the canvas
|
|
||||||
if (!sourceScene)
|
|
||||||
sourceScene = obs_scene_create_private(nullptr);
|
|
||||||
source = obs_source_get_ref(obs_scene_get_source(sourceScene));
|
|
||||||
|
|
||||||
if (sourceSceneItem) {
|
|
||||||
if (obs_sceneitem_get_source(sourceSceneItem) !=
|
|
||||||
rawSource) {
|
|
||||||
obs_sceneitem_remove(sourceSceneItem);
|
|
||||||
sourceSceneItem = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!sourceSceneItem) {
|
|
||||||
sourceSceneItem = obs_scene_add(sourceScene, rawSource);
|
|
||||||
obs_source_release(rawSource);
|
|
||||||
|
|
||||||
obs_sceneitem_set_bounds_type(sourceSceneItem,
|
|
||||||
OBS_BOUNDS_SCALE_INNER);
|
|
||||||
obs_sceneitem_set_bounds_alignment(sourceSceneItem,
|
|
||||||
OBS_ALIGN_CENTER);
|
|
||||||
|
|
||||||
const struct vec2 size = {
|
|
||||||
(float)obs_source_get_width(source),
|
|
||||||
(float)obs_source_get_height(source),
|
|
||||||
};
|
|
||||||
obs_sceneitem_set_bounds(sourceSceneItem, &size);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,27 +4,28 @@
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "window-basic-vcam.hpp"
|
||||||
|
|
||||||
#include "ui_OBSBasicVCamConfig.h"
|
#include "ui_OBSBasicVCamConfig.h"
|
||||||
|
|
||||||
|
struct VCamConfig;
|
||||||
|
|
||||||
class OBSBasicVCamConfig : public QDialog {
|
class OBSBasicVCamConfig : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
VCamConfig config;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void Init();
|
explicit OBSBasicVCamConfig(const VCamConfig &config,
|
||||||
|
QWidget *parent = 0);
|
||||||
static video_t *StartVideo();
|
|
||||||
static void StopVideo();
|
|
||||||
static void DestroyView();
|
|
||||||
|
|
||||||
static void UpdateOutputSource();
|
|
||||||
static void SaveData(obs_data_t *data, bool saving);
|
|
||||||
|
|
||||||
explicit OBSBasicVCamConfig(QWidget *parent = 0);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void OutputTypeChanged(int type);
|
void OutputTypeChanged(int type);
|
||||||
void Save();
|
void UpdateConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::OBSBasicVCamConfig> ui;
|
std::unique_ptr<Ui::OBSBasicVCamConfig> ui;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void Accepted(const VCamConfig &config);
|
||||||
};
|
};
|
||||||
|
|
21
UI/window-basic-vcam.hpp
Normal file
21
UI/window-basic-vcam.hpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
enum VCamOutputType {
|
||||||
|
InternalOutput,
|
||||||
|
SceneOutput,
|
||||||
|
SourceOutput,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VCamInternalType {
|
||||||
|
Default,
|
||||||
|
Preview,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VCamConfig {
|
||||||
|
VCamOutputType type = VCamOutputType::InternalOutput;
|
||||||
|
VCamInternalType internal = VCamInternalType::Default;
|
||||||
|
std::string scene;
|
||||||
|
std::string source;
|
||||||
|
};
|
Loading…
Reference in a new issue