Преглед изворни кода

aja-output-ui: Add the Multi View UI options for new device.

Paul Hindt пре 3 година
родитељ
комит
1cbf9421d4

+ 96 - 3
UI/frontend-plugins/aja-output-ui/AJAOutputUI.cpp

@@ -1,10 +1,15 @@
 #include "AJAOutputUI.h"
 #include "aja-ui-main.h"
 
+#include "../../../plugins/aja/aja-common.hpp"
 #include "../../../plugins/aja/aja-ui-props.hpp"
 #include "../../../plugins/aja/aja-enums.hpp"
+#include "../../../plugins/aja/aja-card-manager.hpp"
 
+#include <ajantv2/includes/ntv2card.h>
+#include <ajantv2/includes/ntv2devicefeatures.h>
 #include <ajantv2/includes/ntv2enums.h>
+#include <ajantv2/includes/ntv2utils.h>
 
 #include <obs-module.h>
 #include <util/platform.h>
@@ -13,19 +18,19 @@
 AJAOutputUI::AJAOutputUI(QWidget *parent) : QDialog(parent), ui(new Ui_Output)
 {
 	ui->setupUi(this);
-
 	setSizeGripEnabled(true);
-
 	setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
 
 	propertiesView = nullptr;
 	previewPropertiesView = nullptr;
+	miscPropertiesView = nullptr;
 }
 
 void AJAOutputUI::ShowHideDialog()
 {
 	SetupPropertiesView();
 	SetupPreviewPropertiesView();
+	SetupMiscPropertiesView();
 
 	setVisible(!isVisible());
 }
@@ -36,7 +41,6 @@ void AJAOutputUI::SetupPropertiesView()
 		delete propertiesView;
 
 	obs_data_t *settings = obs_data_create();
-
 	OBSData data = load_settings(kProgramPropsFilename);
 	if (data) {
 		obs_data_apply(settings, data);
@@ -181,3 +185,92 @@ void AJAOutputUI::PreviewOutputStateChanged(bool active)
 	ui->previewOutputButton->setChecked(active);
 	ui->previewOutputButton->setText(text);
 }
+
+static obs_properties_t *create_misc_props_ui(void *vp)
+{
+	AJAOutputUI *outputUI = (AJAOutputUI *)vp;
+	if (!outputUI)
+		return nullptr;
+	aja::CardManager *cardManager = outputUI->GetCardManager();
+	if (!cardManager)
+		return nullptr;
+
+	bool haveMultiView = false;
+	for (auto &c : *cardManager) {
+		auto deviceID = c.second->GetDeviceID();
+		for (const auto &id : aja::MultiViewCards()) {
+			if (deviceID == id) {
+				haveMultiView = true;
+				break;
+			}
+		}
+	}
+
+	obs_properties_t *props = obs_properties_create();
+	obs_property_t *deviceList = obs_properties_add_list(
+		props, kUIPropDevice.id, obs_module_text(kUIPropDevice.text),
+		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
+	obs_property_t *multiViewEnable = obs_properties_add_bool(
+		props, kUIPropMultiViewEnable.id,
+		obs_module_text(kUIPropMultiViewEnable.text));
+	obs_property_t *multiViewAudioSources = obs_properties_add_list(
+		props, kUIPropMultiViewAudioSource.id,
+		obs_module_text(kUIPropMultiViewAudioSource.text),
+		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
+
+	obs_property_list_clear(deviceList);
+	obs_property_list_clear(multiViewAudioSources);
+
+	NTV2DeviceID firstDeviceID = DEVICE_ID_NOTFOUND;
+	populate_misc_device_list(deviceList, cardManager, firstDeviceID);
+	populate_multi_view_audio_sources(multiViewAudioSources, firstDeviceID);
+	obs_property_set_modified_callback2(deviceList, on_misc_device_selected,
+					    cardManager);
+	obs_property_set_modified_callback2(multiViewEnable,
+					    on_multi_view_toggle, cardManager);
+	obs_property_set_modified_callback2(multiViewAudioSources,
+					    on_multi_view_toggle, cardManager);
+
+	outputUI->ui->label_3->setVisible(haveMultiView);
+	obs_property_set_visible(deviceList, haveMultiView);
+	obs_property_set_visible(multiViewEnable, haveMultiView);
+	obs_property_set_visible(multiViewAudioSources, haveMultiView);
+
+	return props;
+}
+
+void AJAOutputUI::MiscPropertiesChanged()
+{
+	SaveSettings(kMiscPropsFilename, miscPropertiesView->GetSettings());
+}
+
+void AJAOutputUI::SetCardManager(aja::CardManager *cm)
+{
+	cardManager = cm;
+}
+
+aja::CardManager *AJAOutputUI::GetCardManager()
+{
+	return cardManager;
+}
+
+void AJAOutputUI::SetupMiscPropertiesView()
+{
+	if (miscPropertiesView)
+		delete miscPropertiesView;
+
+	obs_data_t *settings = obs_data_create();
+	OBSData data = load_settings(kMiscPropsFilename);
+	if (data) {
+		obs_data_apply(settings, data);
+	}
+
+	miscPropertiesView = new OBSPropertiesView(
+		settings, this, (PropertiesReloadCallback)create_misc_props_ui,
+		nullptr, nullptr, 170);
+
+	ui->miscPropertiesLayout->addWidget(miscPropertiesView);
+	obs_data_release(settings);
+	connect(miscPropertiesView, SIGNAL(Changed()), this,
+		SLOT(MiscPropertiesChanged()));
+}

+ 12 - 3
UI/frontend-plugins/aja-output-ui/AJAOutputUI.h

@@ -5,12 +5,17 @@
 #include "ui_output.h"
 #include "../../UI/properties-view.hpp"
 
+namespace aja {
+class CardManager;
+}
+
 class AJAOutputUI : public QDialog {
 	Q_OBJECT
 private:
 	OBSPropertiesView *propertiesView;
 	OBSPropertiesView *previewPropertiesView;
-
+	OBSPropertiesView *miscPropertiesView;
+	aja::CardManager *cardManager;
 public slots:
 	void on_outputButton_clicked();
 	void PropertiesChanged();
@@ -20,14 +25,18 @@ public slots:
 	void PreviewPropertiesChanged();
 	void PreviewOutputStateChanged(bool);
 
+	void MiscPropertiesChanged();
+
 public:
 	std::unique_ptr<Ui_Output> ui;
 	AJAOutputUI(QWidget *parent);
 
-	void ShowHideDialog();
+	void SetCardManager(aja::CardManager *cm);
+	aja::CardManager *GetCardManager();
 
+	void ShowHideDialog();
 	void SaveSettings(const char *filename, obs_data_t *settings);
-
 	void SetupPropertiesView();
 	void SetupPreviewPropertiesView();
+	void SetupMiscPropertiesView();
 };

+ 18 - 2
UI/frontend-plugins/aja-output-ui/CMakeLists.txt

@@ -44,8 +44,16 @@ set(aja-output-ui_HEADERS
 	../../spinbox-ignorewheel.hpp
 	AJAOutputUI.h
 	aja-ui-main.h
+	../../../plugins/aja/aja-card-manager.hpp
+	../../../plugins/aja/aja-common.hpp
+	../../../plugins/aja/aja-enums.hpp
+	../../../plugins/aja/aja-presets.hpp
+	../../../plugins/aja/aja-props.hpp
+	../../../plugins/aja/aja-routing.hpp
 	../../../plugins/aja/aja-ui-props.hpp
-	../../../plugins/aja/aja-enums.hpp)
+	../../../plugins/aja/aja-vpid-data.hpp
+	../../../plugins/aja/aja-widget-io.hpp
+	)
 
 set(aja-output-ui_SOURCES
 	${aja-output-ui_SOURCES}
@@ -57,7 +65,15 @@ set(aja-output-ui_SOURCES
 	../../combobox-ignorewheel.cpp
 	../../spinbox-ignorewheel.cpp
 	AJAOutputUI.cpp
-	aja-ui-main.cpp)
+	aja-ui-main.cpp
+	../../../plugins/aja/aja-card-manager.cpp
+	../../../plugins/aja/aja-common.cpp
+	../../../plugins/aja/aja-presets.cpp
+	../../../plugins/aja/aja-props.cpp
+	../../../plugins/aja/aja-routing.cpp
+	../../../plugins/aja/aja-vpid-data.cpp
+	../../../plugins/aja/aja-widget-io.cpp
+	)
 
 set(aja-output-ui_UI
 	${aja-output-ui_UI}

+ 169 - 12
UI/frontend-plugins/aja-output-ui/aja-ui-main.cpp

@@ -2,6 +2,8 @@
 #include "AJAOutputUI.h"
 
 #include "../../../plugins/aja/aja-ui-props.hpp"
+#include "../../../plugins/aja/aja-card-manager.hpp"
+#include "../../../plugins/aja/aja-routing.hpp"
 
 #include <obs-module.h>
 #include <obs-frontend-api.h>
@@ -16,13 +18,13 @@
 OBS_DECLARE_MODULE()
 OBS_MODULE_USE_DEFAULT_LOCALE("aja-output-ui", "en-US")
 
-AJAOutputUI *doUI;
+static aja::CardManager *cardManager = nullptr;
+static AJAOutputUI *ajaOutputUI = nullptr;
+static obs_output_t *output = nullptr;
 
 bool main_output_running = false;
 bool preview_output_running = false;
 
-obs_output_t *output;
-
 struct preview_output {
 	bool enabled;
 	obs_source_t *current_source;
@@ -60,7 +62,7 @@ void output_stop()
 	obs_output_stop(output);
 	obs_output_release(output);
 	main_output_running = false;
-	doUI->OutputStateChanged(false);
+	ajaOutputUI->OutputStateChanged(false);
 }
 
 void output_start()
@@ -76,7 +78,7 @@ void output_start()
 
 		main_output_running = started;
 
-		doUI->OutputStateChanged(started);
+		ajaOutputUI->OutputStateChanged(started);
 
 		if (!started)
 			output_stop();
@@ -113,7 +115,7 @@ void preview_output_stop()
 	video_output_close(context.video_queue);
 
 	preview_output_running = false;
-	doUI->PreviewOutputStateChanged(false);
+	ajaOutputUI->PreviewOutputStateChanged(false);
 }
 
 void preview_output_start()
@@ -169,7 +171,7 @@ void preview_output_start()
 		obs_data_release(settings);
 
 		preview_output_running = started;
-		doUI->PreviewOutputStateChanged(started);
+		ajaOutputUI->PreviewOutputStateChanged(started);
 
 		if (!started)
 			preview_output_stop();
@@ -184,6 +186,142 @@ void preview_output_toggle()
 		preview_output_start();
 }
 
+void populate_misc_device_list(obs_property_t *list,
+			       aja::CardManager *cardManager,
+			       NTV2DeviceID &firstDeviceID)
+{
+	for (const auto &iter : *cardManager) {
+		if (!iter.second)
+			continue;
+		if (firstDeviceID == DEVICE_ID_NOTFOUND)
+			firstDeviceID = iter.second->GetDeviceID();
+		obs_property_list_add_string(
+			list, iter.second->GetDisplayName().c_str(),
+			iter.second->GetCardID().c_str());
+	}
+}
+
+void populate_multi_view_audio_sources(obs_property_t *list, NTV2DeviceID id)
+{
+	obs_property_list_clear(list);
+	const QList<NTV2InputSource> kMultiViewAudioInputs = {
+		NTV2_INPUTSOURCE_SDI1,
+		NTV2_INPUTSOURCE_SDI2,
+		NTV2_INPUTSOURCE_SDI3,
+		NTV2_INPUTSOURCE_SDI4,
+	};
+	for (const auto &inp : kMultiViewAudioInputs) {
+		if (NTV2DeviceCanDoInputSource(id, inp)) {
+			std::string inputSourceStr =
+				NTV2InputSourceToString(inp, true);
+			obs_property_list_add_int(list, inputSourceStr.c_str(),
+						  (long long)inp);
+		}
+	}
+}
+
+bool on_misc_device_selected(void *data, obs_properties_t *props,
+			     obs_property_t *list, obs_data_t *settings)
+{
+	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
+	if (!cardID)
+		return false;
+	aja::CardManager *cardManager = (aja::CardManager *)data;
+	if (!cardManager)
+		return false;
+	auto cardEntry = cardManager->GetCardEntry(cardID);
+	if (!cardEntry)
+		return false;
+
+	NTV2DeviceID deviceID = cardEntry->GetDeviceID();
+	bool enableMultiViewUI = NTV2DeviceCanDoHDMIMultiView(deviceID);
+	obs_property_t *multiViewCheckbox =
+		obs_properties_get(props, kUIPropMultiViewEnable.id);
+	obs_property_t *multiViewAudioSource =
+		obs_properties_get(props, kUIPropMultiViewAudioSource.id);
+	populate_multi_view_audio_sources(multiViewAudioSource, deviceID);
+	obs_property_set_enabled(multiViewCheckbox, enableMultiViewUI);
+	obs_property_set_enabled(multiViewAudioSource, enableMultiViewUI);
+	return true;
+}
+
+static void toggle_multi_view(CNTV2Card *card, NTV2InputSource src, bool enable)
+{
+	std::ostringstream oss;
+	for (int i = 0; i < 4; i++) {
+		std::string datastream = std::to_string(i);
+		oss << "sdi[" << datastream << "][0]->hdmi[0][" << datastream
+		    << "];";
+	}
+
+	NTV2DeviceID deviceId = card->GetDeviceID();
+	NTV2AudioSystem audioSys = NTV2InputSourceToAudioSystem(src);
+	if (NTV2DeviceCanDoHDMIMultiView(deviceId)) {
+		NTV2XptConnections cnx;
+		if (aja::Routing::ParseRouteString(oss.str(), cnx)) {
+			card->SetMultiRasterBypassEnable(!enable);
+			if (enable) {
+				card->ApplySignalRoute(cnx, false);
+				if (NTV2DeviceCanDoAudioMixer(deviceId)) {
+					card->SetAudioMixerInputAudioSystem(
+						NTV2_AudioMixerInputMain,
+						audioSys);
+					card->SetAudioMixerInputChannelSelect(
+						NTV2_AudioMixerInputMain,
+						NTV2_AudioChannel1_2);
+					card->SetAudioMixerInputChannelsMute(
+						NTV2_AudioMixerInputAux1,
+						NTV2AudioChannelsMuteAll);
+					card->SetAudioMixerInputChannelsMute(
+						NTV2_AudioMixerInputAux2,
+						NTV2AudioChannelsMuteAll);
+				}
+				card->SetAudioLoopBack(NTV2_AUDIO_LOOPBACK_ON,
+						       audioSys);
+				card->SetAudioOutputMonitorSource(
+					NTV2_AudioChannel1_2, audioSys);
+				card->SetHDMIOutAudioChannels(
+					NTV2_HDMIAudio8Channels);
+				card->SetHDMIOutAudioSource2Channel(
+					NTV2_AudioChannel1_2, audioSys);
+				card->SetHDMIOutAudioSource8Channel(
+					NTV2_AudioChannel1_8, audioSys);
+			} else {
+				card->RemoveConnections(cnx);
+			}
+		}
+	}
+}
+
+bool on_multi_view_toggle(void *data, obs_properties_t *props,
+			  obs_property_t *list, obs_data_t *settings)
+{
+	UNUSED_PARAMETER(props);
+	UNUSED_PARAMETER(list);
+
+	bool multiViewEnabled =
+		obs_data_get_bool(settings, kUIPropMultiViewEnable.id) &&
+		!main_output_running && !preview_output_running;
+	const int audioInputSource =
+		obs_data_get_int(settings, kUIPropMultiViewAudioSource.id);
+	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
+	if (!cardID)
+		return false;
+	aja::CardManager *cardManager = (aja::CardManager *)data;
+	if (!cardManager)
+		return false;
+	CNTV2Card *card = cardManager->GetCard(cardID);
+	if (!card)
+		return false;
+
+	NTV2InputSource inputSource = (NTV2InputSource)audioInputSource;
+	toggle_multi_view(card, inputSource, multiViewEnabled);
+
+	return true;
+}
+
+// MISC PROPS
+
 void on_preview_scene_changed(enum obs_frontend_event event, void *param)
 {
 	auto ctx = (struct preview_output *)param;
@@ -278,10 +416,10 @@ void addOutputUI(void)
 	QMainWindow *window = (QMainWindow *)obs_frontend_get_main_window();
 
 	obs_frontend_push_ui_translation(obs_module_get_string);
-	doUI = new AJAOutputUI(window);
+	ajaOutputUI = new AJAOutputUI(window);
 	obs_frontend_pop_ui_translation();
 
-	auto cb = []() { doUI->ShowHideDialog(); };
+	auto cb = []() { ajaOutputUI->ShowHideDialog(); };
 
 	action->connect(action, &QAction::triggered, cb);
 }
@@ -290,17 +428,21 @@ static void OBSEvent(enum obs_frontend_event event, void *)
 {
 	if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) {
 		OBSData settings = load_settings(kProgramPropsFilename);
-
 		if (settings &&
 		    obs_data_get_bool(settings, kUIPropAutoStartOutput.id))
 			output_start();
 
 		OBSData previewSettings = load_settings(kPreviewPropsFilename);
-
 		if (previewSettings &&
 		    obs_data_get_bool(previewSettings,
 				      kUIPropAutoStartOutput.id))
 			preview_output_start();
+
+		OBSData miscSettings = load_settings(kMiscPropsFilename);
+		if (miscSettings && ajaOutputUI) {
+			on_multi_view_toggle(ajaOutputUI->GetCardManager(),
+					     nullptr, nullptr, miscSettings);
+		}
 	} else if (event == OBS_FRONTEND_EVENT_EXIT) {
 		if (main_output_running)
 			output_stop();
@@ -309,15 +451,30 @@ static void OBSEvent(enum obs_frontend_event event, void *)
 	}
 }
 
+static void aja_loaded(void *data, calldata_t *calldata)
+{
+	// Receive CardManager pointer from the main AJA plugin
+	calldata_get_ptr(calldata, "card_manager", &cardManager);
+	if (ajaOutputUI)
+		ajaOutputUI->SetCardManager(cardManager);
+}
+
 bool obs_module_load(void)
 {
 	CNTV2DeviceScanner scanner;
 	auto numDevices = scanner.GetNumDevices();
-
 	if (numDevices == 0) {
+		blog(LOG_WARNING,
+		     "No AJA devices found, skipping loading AJA UI plugin");
 		return false;
 	}
 
+	// Signal to wait for AJA plugin to finish loading so we can access the CardManager instance
+	auto signal_handler = obs_get_signal_handler();
+	signal_handler_add(signal_handler, "void aja_loaded(ptr card_manager)");
+	signal_handler_connect(signal_handler, "aja_loaded", aja_loaded,
+			       nullptr);
+
 	addOutputUI();
 
 	obs_frontend_add_event_callback(OBSEvent, nullptr);

+ 14 - 0
UI/frontend-plugins/aja-output-ui/aja-ui-main.h

@@ -2,9 +2,23 @@
 
 #include <obs.hpp>
 
+#include <ajantv2/includes/ntv2enums.h>
+namespace aja {
+class CardManager;
+}
+
 static const char *kProgramPropsFilename = "ajaOutputProps.json";
 static const char *kPreviewPropsFilename = "ajaPreviewOutputProps.json";
+static const char *kMiscPropsFilename = "ajaMiscProps.json";
 
 OBSData load_settings(const char *filename);
 void output_toggle();
 void preview_output_toggle();
+void populate_misc_device_list(obs_property_t *list,
+			       aja::CardManager *cardManager,
+			       NTV2DeviceID &firstDeviceID);
+void populate_multi_view_audio_sources(obs_property_t *list, NTV2DeviceID id);
+bool on_misc_device_selected(void *data, obs_properties_t *props,
+			     obs_property_t *list, obs_data_t *settings);
+bool on_multi_view_toggle(void *data, obs_properties_t *props,
+			  obs_property_t *list, obs_data_t *settings);

+ 3 - 0
UI/frontend-plugins/aja-output-ui/data/locale/en-US.ini

@@ -1,3 +1,6 @@
 AJAOutput.Device="AJA I/O Device Output"
 AJAOutput.ProgramOutput="Program Output"
 AJAOutput.PreviewOutput="Preview Output"
+AJAOutput.MiscOutput="Additional Settings"
+AJAOutput.MultiViewEnable="Enable Multi View"
+AJAOutput.MultiViewAudioSource="Multi View Audio Source"

+ 10 - 0
UI/frontend-plugins/aja-output-ui/forms/output.ui

@@ -106,6 +106,16 @@
      </item>
     </layout>
    </item>
+   <item>
+    <widget class="QLabel" name="label_3">
+     <property name="text">
+      <string>AJAOutput.MiscOutput</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QVBoxLayout" name="miscPropertiesLayout"/>
+   </item>
   </layout>
  </widget>
  <resources/>

+ 5 - 0
plugins/aja/aja-common.cpp

@@ -1135,4 +1135,9 @@ VPIDStandard DetermineVPIDStandard(NTV2DeviceID id, IOSelection io,
 	return vpid;
 }
 
+std::vector<NTV2DeviceID> MultiViewCards()
+{
+	return {DEVICE_ID_IOX3};
+}
+
 } // aja

+ 2 - 0
plugins/aja/aja-common.hpp

@@ -98,4 +98,6 @@ extern VPIDStandard DetermineVPIDStandard(NTV2DeviceID id, IOSelection io,
 					  NTV2VideoFormat vf,
 					  NTV2PixelFormat pf, SDITransport trx,
 					  SDITransport4K t4k);
+extern std::vector<NTV2DeviceID> MultiViewCards();
+
 } // aja