Ver código fonte

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.
tytan652 3 anos atrás
pai
commit
7cd7ca80f8

+ 3 - 3
UI/data/locale/en-US.ini

@@ -740,9 +740,9 @@ Basic.Main.VirtualCamConfig="Configure Virtual Camera"
 Basic.VCam.VirtualCamera="Virtual Camera"
 Basic.VCam.VirtualCamera="Virtual Camera"
 Basic.VCam.OutputType="Output Type"
 Basic.VCam.OutputType="Output Type"
 Basic.VCam.OutputSelection="Output Selection"
 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 mode file menu
 Basic.MainMenu.File="&File"
 Basic.MainMenu.File="&File"

+ 11 - 17
UI/forms/OBSBasicVCamConfig.ui

@@ -22,23 +22,7 @@
     </widget>
     </widget>
    </item>
    </item>
    <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>
    <item>
    <item>
     <widget class="QLabel" name="outputSelectionLabel">
     <widget class="QLabel" name="outputSelectionLabel">
@@ -50,6 +34,16 @@
    <item>
    <item>
     <widget class="QComboBox" name="outputSelection"/>
     <widget class="QComboBox" name="outputSelection"/>
    </item>
    </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>
    <item>
     <spacer name="verticalSpacer">
     <spacer name="verticalSpacer">
      <property name="orientation">
      <property name="orientation">

+ 20 - 13
UI/window-basic-main-outputs.cpp

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

+ 2 - 10
UI/window-basic-main-transitions.cpp

@@ -283,10 +283,6 @@ void OBSBasic::OverrideTransition(OBSSource transition)
 		obs_transition_swap_begin(transition, oldTransition);
 		obs_transition_swap_begin(transition, oldTransition);
 		obs_set_output_source(0, transition);
 		obs_set_output_source(0, 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
-		if (vcamEnabled)
-			outputHandler->UpdateVirtualCamOutputSource();
 	}
 	}
 }
 }
 
 
@@ -426,10 +422,6 @@ void OBSBasic::SetTransition(OBSSource transition)
 	ui->transitionRemove->setEnabled(configurable);
 	ui->transitionRemove->setEnabled(configurable);
 	ui->transitionProps->setEnabled(configurable);
 	ui->transitionProps->setEnabled(configurable);
 
 
-	if (vcamEnabled && vcamConfig.type == VCamOutputType::InternalOutput &&
-	    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);
 }
 }
@@ -697,8 +689,8 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force)
 				ui->scenes->blockSignals(false);
 				ui->scenes->blockSignals(false);
 
 
 				if (vcamEnabled &&
 				if (vcamEnabled &&
-				    vcamConfig.internal ==
-					    VCamInternalType::Preview)
+				    vcamConfig.type ==
+					    VCamOutputType::PreviewOutput)
 					outputHandler
 					outputHandler
 						->UpdateVirtualCamOutputSource();
 						->UpdateVirtualCamOutputSource();
 
 

+ 56 - 12
UI/window-basic-main.cpp

@@ -795,11 +795,11 @@ void OBSBasic::Save(const char *file)
 	if (vcamEnabled) {
 	if (vcamEnabled) {
 		OBSDataAutoRelease obj = obs_data_create();
 		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) {
 		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;
 			break;
 		case VCamOutputType::SceneOutput:
 		case VCamOutputType::SceneOutput:
 			obs_data_set_string(obj, "scene",
 			obs_data_set_string(obj, "scene",
@@ -1239,9 +1239,26 @@ retryScene:
 		OBSDataAutoRelease obj =
 		OBSDataAutoRelease obj =
 			obs_data_get_obj(data, "virtual-camera");
 			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.scene = obs_data_get_string(obj, "scene");
 		vcamConfig.source = obs_data_get_string(obj, "source");
 		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
 	/* Reset VCam to default to clear its private scene and any references
 	 * it holds. It will be reconfigured during loading. */
 	 * it holds. It will be reconfigured during loading. */
 	if (vcamEnabled) {
 	if (vcamEnabled) {
-		vcamConfig.type = VCamOutputType::InternalOutput;
-		vcamConfig.internal = VCamInternalType::Default;
+		vcamConfig.type = VCamOutputType::ProgramView;
 		outputHandler->UpdateVirtualCamOutputSource();
 		outputHandler->UpdateVirtualCamOutputSource();
 	}
 	}
 
 
@@ -5300,8 +5316,7 @@ void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
 
 
 	SetCurrentScene(source);
 	SetCurrentScene(source);
 
 
-	if (vcamEnabled && vcamConfig.type == VCamOutputType::InternalOutput &&
-	    vcamConfig.internal == VCamInternalType::Preview)
+	if (vcamEnabled && vcamConfig.type == VCamOutputType::PreviewOutput)
 		outputHandler->UpdateVirtualCamOutputSource();
 		outputHandler->UpdateVirtualCamOutputSource();
 
 
 	if (api)
 	if (api)
@@ -7935,6 +7950,13 @@ void OBSBasic::OnVirtualCamStop(int)
 	blog(LOG_INFO, VIRTUAL_CAM_STOP);
 	blog(LOG_INFO, VIRTUAL_CAM_STOP);
 
 
 	OnDeactivate();
 	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()
 void OBSBasic::on_streamButton_clicked()
@@ -8089,10 +8111,13 @@ void OBSBasic::VCamButtonClicked()
 
 
 void OBSBasic::VCamConfigButtonClicked()
 void OBSBasic::VCamConfigButtonClicked()
 {
 {
-	OBSBasicVCamConfig dialog(vcamConfig, this);
+	OBSBasicVCamConfig dialog(vcamConfig, outputHandler->VirtualCamActive(),
+				  this);
 
 
 	connect(&dialog, &OBSBasicVCamConfig::Accepted, this,
 	connect(&dialog, &OBSBasicVCamConfig::Accepted, this,
 		&OBSBasic::UpdateVirtualCamConfig);
 		&OBSBasic::UpdateVirtualCamConfig);
+	connect(&dialog, &OBSBasicVCamConfig::AcceptedAndRestart, this,
+		&OBSBasic::RestartVirtualCam);
 
 
 	dialog.exec();
 	dialog.exec();
 }
 }
@@ -8104,6 +8129,25 @@ void OBSBasic::UpdateVirtualCamConfig(const VCamConfig &config)
 	outputHandler->UpdateVirtualCamOutputSource();
 	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()
 void OBSBasic::on_settingsButton_clicked()
 {
 {
 	on_action_Settings_triggered();
 	on_action_Settings_triggered();

+ 4 - 0
UI/window-basic-main.hpp

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

+ 51 - 18
UI/window-basic-vcam-config.cpp

@@ -5,35 +5,55 @@
 #include <util/util.hpp>
 #include <util/util.hpp>
 #include <util/platform.h>
 #include <util/platform.h>
 
 
+#include <QStandardItem>
+
 OBSBasicVCamConfig::OBSBasicVCamConfig(const VCamConfig &_config,
 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);
 	setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
 
 
 	ui->setupUi(this);
 	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,
 	connect(ui->outputType, SIGNAL(currentIndexChanged(int)), this,
-		SLOT(OutputTypeChanged(int)));
+		SLOT(OutputTypeChanged()));
 
 
 	connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
 	connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
 		&OBSBasicVCamConfig::UpdateConfig);
 		&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;
 	auto list = ui->outputSelection;
 	list->clear();
 	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;
 		break;
-
 	case VCamOutputType::SceneOutput: {
 	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();
@@ -45,7 +65,6 @@ void OBSBasicVCamConfig::OutputTypeChanged(int type)
 		}
 		}
 		break;
 		break;
 	}
 	}
-
 	case VCamOutputType::SourceOutput: {
 	case VCamOutputType::SourceOutput: {
 		// Sources in alphabetical order
 		// Sources in alphabetical order
 		std::vector<std::string> sources;
 		std::vector<std::string> sources;
@@ -81,15 +100,25 @@ void OBSBasicVCamConfig::OutputTypeChanged(int type)
 		break;
 		break;
 	}
 	}
 	}
 	}
+
+	if (!vcamActive)
+		return;
+
+	requireRestart = (activeType == VCamOutputType::ProgramView &&
+			  type != VCamOutputType::ProgramView) ||
+			 (activeType != VCamOutputType::ProgramView &&
+			  type == VCamOutputType::ProgramView);
+
+	ui->warningLabel->setVisible(requireRestart);
 }
 }
 
 
 void OBSBasicVCamConfig::UpdateConfig()
 void OBSBasicVCamConfig::UpdateConfig()
 {
 {
-	VCamOutputType type = (VCamOutputType)ui->outputType->currentIndex();
+	VCamOutputType type =
+		(VCamOutputType)ui->outputType->currentData().toInt();
 	switch (type) {
 	switch (type) {
-	case VCamOutputType::InternalOutput:
-		config.internal =
-			(VCamInternalType)ui->outputSelection->currentIndex();
+	case VCamOutputType::ProgramView:
+	case VCamOutputType::PreviewOutput:
 		break;
 		break;
 	case VCamOutputType::SceneOutput:
 	case VCamOutputType::SceneOutput:
 		config.scene = ui->outputSelection->currentText().toStdString();
 		config.scene = ui->outputSelection->currentText().toStdString();
@@ -105,5 +134,9 @@ void OBSBasicVCamConfig::UpdateConfig()
 
 
 	config.type = type;
 	config.type = type;
 
 
-	emit Accepted(config);
+	if (requireRestart) {
+		emit AcceptedAndRestart(config);
+	} else {
+		emit Accepted(config);
+	}
 }
 }

+ 7 - 2
UI/window-basic-vcam-config.hpp

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

+ 5 - 3
UI/window-basic-vcam.hpp

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