UI: Use main video on the virtual camera if program

This change allows the virtual camera to really output what is in the
program view, some plugin interract with this view but their changes
does not appear on the virtual camera.
This commit is contained in:
tytan652 2022-11-15 10:00:41 +01:00 committed by Lain
parent 2be0550e9a
commit 7cd7ca80f8
9 changed files with 159 additions and 78 deletions

View file

@ -740,9 +740,9 @@ Basic.Main.VirtualCamConfig="Configure Virtual Camera"
Basic.VCam.VirtualCamera="Virtual Camera"
Basic.VCam.OutputType="Output Type"
Basic.VCam.OutputSelection="Output Selection"
Basic.VCam.Internal="Internal"
Basic.VCam.InternalDefault="Program Output (Default)"
Basic.VCam.InternalPreview="Preview Output"
Basic.VCam.OutputType.Program="Program (Default)"
Basic.VCam.OutputSelection.NoSelection="No selection for this output type"
Basic.VCam.RestartWarning="The virtual camera will be restarted to apply this change"
# basic mode file menu
Basic.MainMenu.File="&File"

View file

@ -22,23 +22,7 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="outputType">
<item>
<property name="text">
<string>Basic.VCam.Internal</string>
</property>
</item>
<item>
<property name="text">
<string>Basic.Scene</string>
</property>
</item>
<item>
<property name="text">
<string>Basic.Main.Source</string>
</property>
</item>
</widget>
<widget class="QComboBox" name="outputType"/>
</item>
<item>
<widget class="QLabel" name="outputSelectionLabel">
@ -50,6 +34,16 @@
<item>
<widget class="QComboBox" name="outputSelection"/>
</item>
<item>
<widget class="QLabel" name="warningLabel">
<property name="text">
<string>Basic.VCam.RestartWarning</string>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View file

@ -301,13 +301,17 @@ bool BasicOutputHandler::StartVirtualCam()
if (!main->vcamEnabled)
return false;
if (!virtualCamView)
bool typeIsProgram = main->vcamConfig.type ==
VCamOutputType::ProgramView;
if (!virtualCamView && !typeIsProgram)
virtualCamView = obs_view_create();
UpdateVirtualCamOutputSource();
if (!virtualCamVideo) {
virtualCamVideo = obs_view_add(virtualCamView);
virtualCamVideo = typeIsProgram ? obs_get_video()
: obs_view_add(virtualCamView);
if (!virtualCamVideo)
return false;
@ -361,19 +365,17 @@ void BasicOutputHandler::UpdateVirtualCamOutputSource()
OBSSourceAutoRelease source;
switch (main->vcamConfig.type) {
case VCamOutputType::InternalOutput:
case VCamOutputType::Invalid:
case VCamOutputType::ProgramView:
DestroyVirtualCameraScene();
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;
}
return;
case VCamOutputType::PreviewOutput: {
DestroyVirtualCameraScene();
OBSSource s = main->GetCurrentSceneSource();
obs_source_get_ref(s);
source = s.Get();
break;
}
case VCamOutputType::SceneOutput:
DestroyVirtualCameraScene();
source = obs_get_source_by_name(main->vcamConfig.scene.c_str());
@ -418,6 +420,11 @@ void BasicOutputHandler::UpdateVirtualCamOutputSource()
void BasicOutputHandler::DestroyVirtualCamView()
{
if (main->vcamConfig.type == VCamOutputType::ProgramView) {
virtualCamVideo = nullptr;
return;
}
obs_view_remove(virtualCamView);
obs_view_set_source(virtualCamView, 0, nullptr);
virtualCamVideo = nullptr;

View file

@ -283,10 +283,6 @@ void OBSBasic::OverrideTransition(OBSSource transition)
obs_transition_swap_begin(transition, oldTransition);
obs_set_output_source(0, transition);
obs_transition_swap_end(transition, oldTransition);
// Transition overrides don't raise an event so we need to call update directly
if (vcamEnabled)
outputHandler->UpdateVirtualCamOutputSource();
}
}
@ -426,10 +422,6 @@ void OBSBasic::SetTransition(OBSSource transition)
ui->transitionRemove->setEnabled(configurable);
ui->transitionProps->setEnabled(configurable);
if (vcamEnabled && vcamConfig.type == VCamOutputType::InternalOutput &&
vcamConfig.internal == VCamInternalType::Default)
outputHandler->UpdateVirtualCamOutputSource();
if (api)
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_CHANGED);
}
@ -697,8 +689,8 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force)
ui->scenes->blockSignals(false);
if (vcamEnabled &&
vcamConfig.internal ==
VCamInternalType::Preview)
vcamConfig.type ==
VCamOutputType::PreviewOutput)
outputHandler
->UpdateVirtualCamOutputSource();

View file

@ -795,11 +795,11 @@ void OBSBasic::Save(const char *file)
if (vcamEnabled) {
OBSDataAutoRelease obj = obs_data_create();
obs_data_set_int(obj, "type", (int)vcamConfig.type);
obs_data_set_int(obj, "type2", (int)vcamConfig.type);
switch (vcamConfig.type) {
case VCamOutputType::InternalOutput:
obs_data_set_int(obj, "internal",
(int)vcamConfig.internal);
case VCamOutputType::Invalid:
case VCamOutputType::ProgramView:
case VCamOutputType::PreviewOutput:
break;
case VCamOutputType::SceneOutput:
obs_data_set_string(obj, "scene",
@ -1239,9 +1239,26 @@ retryScene:
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.type =
(VCamOutputType)obs_data_get_int(obj, "type2");
if (vcamConfig.type == VCamOutputType::Invalid)
vcamConfig.type =
(VCamOutputType)obs_data_get_int(obj, "type");
if (vcamConfig.type == VCamOutputType::Invalid) {
VCamInternalType internal =
(VCamInternalType)obs_data_get_int(obj,
"internal");
switch (internal) {
case VCamInternalType::Default:
vcamConfig.type = VCamOutputType::ProgramView;
break;
case VCamInternalType::Preview:
vcamConfig.type = VCamOutputType::PreviewOutput;
break;
}
}
vcamConfig.scene = obs_data_get_string(obj, "scene");
vcamConfig.source = obs_data_get_string(obj, "source");
}
@ -4873,8 +4890,7 @@ void OBSBasic::ClearSceneData()
/* Reset VCam to default to clear its private scene and any references
* it holds. It will be reconfigured during loading. */
if (vcamEnabled) {
vcamConfig.type = VCamOutputType::InternalOutput;
vcamConfig.internal = VCamInternalType::Default;
vcamConfig.type = VCamOutputType::ProgramView;
outputHandler->UpdateVirtualCamOutputSource();
}
@ -5300,8 +5316,7 @@ void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
SetCurrentScene(source);
if (vcamEnabled && vcamConfig.type == VCamOutputType::InternalOutput &&
vcamConfig.internal == VCamInternalType::Preview)
if (vcamEnabled && vcamConfig.type == VCamOutputType::PreviewOutput)
outputHandler->UpdateVirtualCamOutputSource();
if (api)
@ -7935,6 +7950,13 @@ void OBSBasic::OnVirtualCamStop(int)
blog(LOG_INFO, VIRTUAL_CAM_STOP);
OnDeactivate();
if (!restartingVCam)
return;
/* Restarting needs to be delayed to make sure that the virtual camera
* implementation is stopped and avoid race condition. */
QTimer::singleShot(100, this, &OBSBasic::RestartingVirtualCam);
}
void OBSBasic::on_streamButton_clicked()
@ -8089,10 +8111,13 @@ void OBSBasic::VCamButtonClicked()
void OBSBasic::VCamConfigButtonClicked()
{
OBSBasicVCamConfig dialog(vcamConfig, this);
OBSBasicVCamConfig dialog(vcamConfig, outputHandler->VirtualCamActive(),
this);
connect(&dialog, &OBSBasicVCamConfig::Accepted, this,
&OBSBasic::UpdateVirtualCamConfig);
connect(&dialog, &OBSBasicVCamConfig::AcceptedAndRestart, this,
&OBSBasic::RestartVirtualCam);
dialog.exec();
}
@ -8104,6 +8129,25 @@ void OBSBasic::UpdateVirtualCamConfig(const VCamConfig &config)
outputHandler->UpdateVirtualCamOutputSource();
}
void OBSBasic::RestartVirtualCam(const VCamConfig &config)
{
restartingVCam = true;
StopVirtualCam();
vcamConfig = config;
}
void OBSBasic::RestartingVirtualCam()
{
if (!restartingVCam)
return;
outputHandler->UpdateVirtualCamOutputSource();
StartVirtualCam();
restartingVCam = false;
}
void OBSBasic::on_settingsButton_clicked()
{
on_action_Settings_triggered();

View file

@ -656,6 +656,8 @@ private:
void UpdatePreviewOverflowSettings();
bool restartingVCam = false;
public slots:
void DeferSaveBegin();
void DeferSaveEnd();
@ -830,6 +832,8 @@ private slots:
void ResetProxyStyleSliders();
void UpdateVirtualCamConfig(const VCamConfig &config);
void RestartVirtualCam(const VCamConfig &config);
void RestartingVirtualCam();
private:
/* OBS Callbacks */

View file

@ -5,35 +5,55 @@
#include <util/util.hpp>
#include <util/platform.h>
#include <QStandardItem>
OBSBasicVCamConfig::OBSBasicVCamConfig(const VCamConfig &_config,
QWidget *parent)
: config(_config), QDialog(parent), ui(new Ui::OBSBasicVCamConfig)
bool _vcamActive, QWidget *parent)
: config(_config),
vcamActive(_vcamActive),
activeType(_config.type),
QDialog(parent),
ui(new Ui::OBSBasicVCamConfig)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->setupUi(this);
ui->outputType->setCurrentIndex(config.type);
OutputTypeChanged(config.type);
ui->outputType->addItem(QTStr("Basic.VCam.OutputType.Program"),
(int)VCamOutputType::ProgramView);
ui->outputType->addItem(QTStr("Preview"),
(int)VCamOutputType::PreviewOutput);
ui->outputType->addItem(QTStr("Basic.Scene"),
(int)VCamOutputType::SceneOutput);
ui->outputType->addItem(QTStr("Basic.Main.Source"),
(int)VCamOutputType::SourceOutput);
ui->outputType->setCurrentIndex(
ui->outputType->findData((int)config.type));
OutputTypeChanged();
connect(ui->outputType, SIGNAL(currentIndexChanged(int)), this,
SLOT(OutputTypeChanged(int)));
SLOT(OutputTypeChanged()));
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
&OBSBasicVCamConfig::UpdateConfig);
}
void OBSBasicVCamConfig::OutputTypeChanged(int type)
void OBSBasicVCamConfig::OutputTypeChanged()
{
VCamOutputType type =
(VCamOutputType)ui->outputType->currentData().toInt();
ui->outputSelection->setDisabled(false);
auto list = ui->outputSelection;
list->clear();
switch ((VCamOutputType)type) {
case VCamOutputType::InternalOutput:
list->addItem(QTStr("Basic.VCam.InternalDefault"));
list->addItem(QTStr("Basic.VCam.InternalPreview"));
list->setCurrentIndex(config.internal);
switch (type) {
case VCamOutputType::Invalid:
case VCamOutputType::ProgramView:
case VCamOutputType::PreviewOutput:
ui->outputSelection->setDisabled(true);
list->addItem(QTStr("Basic.VCam.OutputSelection.NoSelection"));
break;
case VCamOutputType::SceneOutput: {
// Scenes in default order
BPtr<char *> scenes = obs_frontend_get_scene_names();
@ -45,7 +65,6 @@ void OBSBasicVCamConfig::OutputTypeChanged(int type)
}
break;
}
case VCamOutputType::SourceOutput: {
// Sources in alphabetical order
std::vector<std::string> sources;
@ -81,15 +100,25 @@ void OBSBasicVCamConfig::OutputTypeChanged(int type)
break;
}
}
if (!vcamActive)
return;
requireRestart = (activeType == VCamOutputType::ProgramView &&
type != VCamOutputType::ProgramView) ||
(activeType != VCamOutputType::ProgramView &&
type == VCamOutputType::ProgramView);
ui->warningLabel->setVisible(requireRestart);
}
void OBSBasicVCamConfig::UpdateConfig()
{
VCamOutputType type = (VCamOutputType)ui->outputType->currentIndex();
VCamOutputType type =
(VCamOutputType)ui->outputType->currentData().toInt();
switch (type) {
case VCamOutputType::InternalOutput:
config.internal =
(VCamInternalType)ui->outputSelection->currentIndex();
case VCamOutputType::ProgramView:
case VCamOutputType::PreviewOutput:
break;
case VCamOutputType::SceneOutput:
config.scene = ui->outputSelection->currentText().toStdString();
@ -105,5 +134,9 @@ void OBSBasicVCamConfig::UpdateConfig()
config.type = type;
emit Accepted(config);
if (requireRestart) {
emit AcceptedAndRestart(config);
} else {
emit Accepted(config);
}
}

View file

@ -15,12 +15,16 @@ class OBSBasicVCamConfig : public QDialog {
VCamConfig config;
bool vcamActive;
VCamOutputType activeType;
bool requireRestart;
public:
explicit OBSBasicVCamConfig(const VCamConfig &config,
explicit OBSBasicVCamConfig(const VCamConfig &config, bool VCamActive,
QWidget *parent = 0);
private slots:
void OutputTypeChanged(int type);
void OutputTypeChanged();
void UpdateConfig();
private:
@ -28,4 +32,5 @@ private:
signals:
void Accepted(const VCamConfig &config);
void AcceptedAndRestart(const VCamConfig &config);
};

View file

@ -3,19 +3,21 @@
#include <string>
enum VCamOutputType {
InternalOutput,
Invalid,
SceneOutput,
SourceOutput,
ProgramView,
PreviewOutput,
};
// Kept for config upgrade
enum VCamInternalType {
Default,
Preview,
};
struct VCamConfig {
VCamOutputType type = VCamOutputType::InternalOutput;
VCamInternalType internal = VCamInternalType::Default;
VCamOutputType type = VCamOutputType::ProgramView;
std::string scene;
std::string source;
};