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

This commit is contained in:
Paul Hindt 2022-01-07 18:45:08 -08:00 committed by Colin Edwards
parent 9d02ca0fef
commit 1cbf9421d4
9 changed files with 329 additions and 20 deletions

View File

@ -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()));
}

View File

@ -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 SetCardManager(aja::CardManager *cm);
aja::CardManager *GetCardManager();
void ShowHideDialog();
void SaveSettings(const char *filename, obs_data_t *settings);
void SetupPropertiesView();
void SetupPreviewPropertiesView();
void SetupMiscPropertiesView();
};

View File

@ -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}

View File

@ -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);

View File

@ -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);

View File

@ -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"

View File

@ -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/>

View File

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

View File

@ -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