Browse Source

aja: Refactor, clean-up and fix bugs in the signal routing system, and add SDITransport UI option to assist signal routing.

Paul Hindt 3 years ago
parent
commit
f09137a2e0

+ 32 - 18
UI/frontend-plugins/aja-output-ui/AJAOutputUI.cpp

@@ -42,15 +42,22 @@ void AJAOutputUI::SetupPropertiesView()
 		obs_data_apply(settings, data);
 	} else {
 		// apply default settings
-		obs_data_set_int(settings, kUIPropOutput.id,
-				 static_cast<long long>(IOSelection::Invalid));
-		obs_data_set_int(settings, kUIPropVideoFormatSelect.id,
-				 static_cast<long long>(NTV2_FORMAT_720p_5994));
-		obs_data_set_int(settings, kUIPropPixelFormatSelect.id,
-				 static_cast<long long>(NTV2_FBF_8BIT_YCBCR));
-		obs_data_set_int(settings, kUIPropSDI4KTransport.id,
-				 static_cast<long long>(
-					 SDI4KTransport::TwoSampleInterleave));
+		obs_data_set_default_int(
+			settings, kUIPropOutput.id,
+			static_cast<long long>(IOSelection::Invalid));
+		obs_data_set_default_int(
+			settings, kUIPropVideoFormatSelect.id,
+			static_cast<long long>(NTV2_FORMAT_720p_5994));
+		obs_data_set_default_int(
+			settings, kUIPropPixelFormatSelect.id,
+			static_cast<long long>(NTV2_FBF_8BIT_YCBCR));
+		obs_data_set_default_int(
+			settings, kUIPropSDITransport.id,
+			static_cast<long long>(SDITransport::SingleLink));
+		obs_data_set_default_int(
+			settings, kUIPropSDITransport4K.id,
+			static_cast<long long>(
+				SDITransport4K::TwoSampleInterleave));
 	}
 
 	// Assign an ID to the program output plugin instance for channel usage tracking
@@ -93,15 +100,22 @@ void AJAOutputUI::SetupPreviewPropertiesView()
 		obs_data_apply(settings, data);
 	} else {
 		// apply default settings
-		obs_data_set_int(settings, kUIPropOutput.id,
-				 static_cast<long long>(IOSelection::Invalid));
-		obs_data_set_int(settings, kUIPropVideoFormatSelect.id,
-				 static_cast<long long>(NTV2_FORMAT_720p_5994));
-		obs_data_set_int(settings, kUIPropPixelFormatSelect.id,
-				 static_cast<long long>(NTV2_FBF_8BIT_YCBCR));
-		obs_data_set_int(settings, kUIPropSDI4KTransport.id,
-				 static_cast<long long>(
-					 SDI4KTransport::TwoSampleInterleave));
+		obs_data_set_default_int(
+			settings, kUIPropOutput.id,
+			static_cast<long long>(IOSelection::Invalid));
+		obs_data_set_default_int(
+			settings, kUIPropVideoFormatSelect.id,
+			static_cast<long long>(NTV2_FORMAT_720p_5994));
+		obs_data_set_default_int(
+			settings, kUIPropPixelFormatSelect.id,
+			static_cast<long long>(NTV2_FBF_8BIT_YCBCR));
+		obs_data_set_default_int(
+			settings, kUIPropSDITransport.id,
+			static_cast<long long>(SDITransport::SingleLink));
+		obs_data_set_default_int(
+			settings, kUIPropSDITransport4K.id,
+			static_cast<long long>(
+				SDITransport4K::TwoSampleInterleave));
 	}
 
 	// Assign an ID to the program output plugin instance for channel usage tracking

+ 4 - 0
plugins/aja/CMakeLists.txt

@@ -31,9 +31,11 @@ set(aja_SOURCES
 	aja-card-manager.cpp
 	aja-common.cpp
 	aja-output.cpp
+	aja-presets.cpp
 	aja-props.cpp
 	aja-routing.cpp
 	aja-source.cpp
+	aja-vpid-data.cpp
 	aja-widget-io.cpp)
 
 set(aja_HEADERS
@@ -42,9 +44,11 @@ set(aja_HEADERS
 	aja-enums.hpp
 	aja-ui-props.hpp
 	aja-output.hpp
+	aja-presets.hpp
 	aja-props.hpp
 	aja-routing.hpp
 	aja-source.hpp
+	aja-vpid-data.hpp
 	aja-widget-io.hpp)
 
 # macOS

+ 20 - 0
plugins/aja/aja-card-manager.cpp

@@ -589,6 +589,14 @@ size_t CardManager::NumCardEntries() const
 	return mCardEntries.size();
 }
 
+CNTV2Card *CardManager::GetCard(const std::string &cardID)
+{
+	auto entry = GetCardEntry(cardID);
+	if (entry)
+		return entry->GetCard();
+	return nullptr;
+}
+
 const CardEntryPtr CardManager::GetCardEntry(const std::string &cardID) const
 {
 	const std::lock_guard<std::mutex> lock(mMutex);
@@ -605,4 +613,16 @@ const CardEntries &CardManager::GetCardEntries() const
 	return mCardEntries;
 }
 
+const CardEntries::iterator CardManager::begin()
+{
+	const std::lock_guard<std::mutex> lock(mMutex);
+	return mCardEntries.begin();
+}
+
+const CardEntries::iterator CardManager::end()
+{
+	const std::lock_guard<std::mutex> lock(mMutex);
+	return mCardEntries.end();
+}
+
 } // aja

+ 3 - 0
plugins/aja/aja-card-manager.hpp

@@ -85,8 +85,11 @@ public:
 	void EnumerateCards();
 
 	size_t NumCardEntries() const;
+	CNTV2Card *GetCard(const std::string &cardID);
 	const CardEntryPtr GetCardEntry(const std::string &cardID) const;
 	const CardEntries &GetCardEntries() const;
+	const CardEntries::iterator begin();
+	const CardEntries::iterator end();
 
 private:
 	CardManager() = default;

+ 252 - 23
plugins/aja/aja-common.cpp

@@ -3,6 +3,7 @@
 #include "aja-ui-props.hpp"
 #include "aja-props.hpp"
 
+#include <ajantv2/includes/ntv2debug.h>
 #include <ajantv2/includes/ntv2devicescanner.h>
 #include <ajantv2/includes/ntv2devicefeatures.h>
 #include <ajantv2/includes/ntv2utils.h>
@@ -160,8 +161,6 @@ void populate_video_format_list(NTV2DeviceID deviceID, obs_property_t *list,
 		orderedStandards.push_back(NTV2_STANDARD_720);
 		orderedStandards.push_back(NTV2_STANDARD_1080);
 		orderedStandards.push_back(NTV2_STANDARD_1080p);
-	}
-	if (NTV2DeviceCanDo2KVideo(deviceID)) {
 		orderedStandards.push_back(NTV2_STANDARD_2K);
 		orderedStandards.push_back(NTV2_STANDARD_2Kx1080p);
 		orderedStandards.push_back(NTV2_STANDARD_2Kx1080i);
@@ -205,17 +204,27 @@ void populate_pixel_format_list(NTV2DeviceID deviceID, obs_property_t *list)
 	}
 }
 
+void populate_sdi_transport_list(obs_property_t *list, IOSelection io)
+{
+	for (int i = 0; i < (int)SDITransport::Unknown; i++) {
+		SDITransport sdi_trx = static_cast<SDITransport>(i);
+		obs_property_list_add_int(
+			list, aja::SDITransportToString(sdi_trx).c_str(),
+			static_cast<long long>(sdi_trx));
+	}
+}
+
 void populate_sdi_4k_transport_list(obs_property_t *list)
 {
 	obs_property_list_add_int(
 		list,
-		aja::SDI4KTransportToString(SDI4KTransport::Squares).c_str(),
-		static_cast<long long>(SDI4KTransport::Squares));
+		aja::SDITransport4KToString(SDITransport4K::Squares).c_str(),
+		static_cast<long long>(SDITransport4K::Squares));
 	obs_property_list_add_int(
 		list,
-		aja::SDI4KTransportToString(SDI4KTransport::TwoSampleInterleave)
+		aja::SDITransport4KToString(SDITransport4K::TwoSampleInterleave)
 			.c_str(),
-		static_cast<long long>(SDI4KTransport::TwoSampleInterleave));
+		static_cast<long long>(SDITransport4K::TwoSampleInterleave));
 }
 
 bool aja_video_format_changed(obs_properties_t *props, obs_property_t *list,
@@ -244,8 +253,7 @@ bool aja_video_format_changed(obs_properties_t *props, obs_property_t *list,
 	}
 
 	obs_property_t *sdi_4k_trx =
-		obs_properties_get(props, kUIPropSDI4KTransport.id);
-
+		obs_properties_get(props, kUIPropSDITransport4K.id);
 	obs_property_set_visible(sdi_4k_trx, NTV2_IS_4K_VIDEO_FORMAT(vid_fmt));
 
 	return true;
@@ -316,21 +324,13 @@ void GetSortedVideoFormats(NTV2DeviceID id, const VideoStandardList &standards,
 	     i < (size_t)NTV2_MAX_NUM_VIDEO_FORMATS; i++) {
 		NTV2VideoFormat fmt = (NTV2VideoFormat)i;
 		NTV2Standard standard = GetNTV2StandardFromVideoFormat(fmt);
-
-		bool addFmt = true;
-
-		if (id != DEVICE_ID_NOTFOUND) {
-			addFmt = NTV2DeviceCanDoVideoFormat(id, fmt);
-		}
-
-		if (addFmt) {
+		if (id != DEVICE_ID_NOTFOUND &&
+		    NTV2DeviceCanDoVideoFormat(id, fmt)) {
 			if (videoFormatMap.count(standard)) {
 				videoFormatMap.at(standard).push_back(fmt);
 			} else {
 				std::vector<NTV2VideoFormat> v;
-
 				v.push_back(fmt);
-
 				videoFormatMap.insert(
 					std::pair<NTV2Standard,
 						  std::vector<NTV2VideoFormat>>(
@@ -371,6 +371,28 @@ void GetSortedVideoFormats(NTV2DeviceID id, const VideoStandardList &standards,
 	}
 }
 
+NTV2VideoFormat HandleSpecialCaseFormats(IOSelection io, NTV2VideoFormat vf,
+					 NTV2DeviceID id)
+{
+	// 1080p Level-B formats and ST372M
+	if (NTV2_VIDEO_FORMAT_IS_B(vf) &&
+	    !(IsSDITwoWireIOSelection(io) && NTV2_IS_HD_VIDEO_FORMAT(vf))) {
+		vf = aja::GetLevelAFormatForLevelBFormat(vf);
+	}
+	// UHD/4K Square Division auto-detect
+	if ((io == IOSelection::SDI1__4 || io == IOSelection::SDI5__8) &&
+	    NTV2_IS_HD_VIDEO_FORMAT(vf)) {
+		vf = GetQuadSizedVideoFormat(vf, true);
+	}
+	// Kona5/io4K+ auto-detection of UHD/4K 6G/12G SDI formats.
+	if (aja::IsSDIOneWireIOSelection(io) && NTV2_IS_4K_VIDEO_FORMAT(vf) &&
+	    !NTV2_IS_SQUARE_DIVISION_FORMAT(vf) &&
+	    !NTV2DeviceCanDo12gRouting(id)) {
+		vf = GetQuadSizedVideoFormat(GetQuarterSizedVideoFormat(vf));
+	}
+	return vf;
+}
+
 uint32_t CardNumFramestores(NTV2DeviceID id)
 {
 	auto numFramestores = NTV2DeviceGetNumFrameStores(id);
@@ -495,7 +517,10 @@ bool IsIODevice(NTV2DeviceID id)
 		id == DEVICE_ID_IOIP_2022 || id == DEVICE_ID_IOIP_2110);
 }
 
-bool IsRetailSDI12G(NTV2DeviceID id)
+/* Kona5 retail firmware and io4K+ have limited support for 6G/12G SDI
+ * where SDI 1 is capable of capture and SDI 3 is capable of output.
+ */
+bool IsRetail12GSDICard(NTV2DeviceID id)
 {
 	return (id == DEVICE_ID_KONA5 || id == DEVICE_ID_IO4KPLUS);
 }
@@ -505,18 +530,47 @@ bool IsOutputOnlyDevice(NTV2DeviceID id)
 	return id == DEVICE_ID_TTAP_PRO;
 }
 
-std::string SDI4KTransportToString(SDI4KTransport mode)
+std::string SDITransportToString(SDITransport mode)
+{
+	std::string str = "";
+	switch (mode) {
+	case SDITransport::SingleLink:
+		str = "SD/HD Single Link";
+		break;
+	case SDITransport::HDDualLink:
+		str = "HD Dual-Link";
+		break;
+	case SDITransport::SDI3Ga:
+		str = "3G Level-A (3Ga)";
+		break;
+	case SDITransport::SDI3Gb:
+		str = "3G Level-B (3Gb)";
+		break;
+	case SDITransport::SDI6G:
+		str = "6G";
+		break;
+	case SDITransport::SDI12G:
+		str = "12G";
+		break;
+	case SDITransport::Unknown:
+		str = "Unknown";
+		break;
+	}
+	return str;
+}
+
+std::string SDITransport4KToString(SDITransport4K mode)
 {
 	std::string str = "";
 	switch (mode) {
-	case SDI4KTransport::Squares:
+	case SDITransport4K::Squares:
 		str = "Squares";
 		break;
-	case SDI4KTransport::TwoSampleInterleave:
+	case SDITransport4K::TwoSampleInterleave:
 		str = "2SI";
 		break;
 	default:
-	case SDI4KTransport::Unknown:
+	case SDITransport4K::Unknown:
 		str = "Unknown";
 		break;
 	}
@@ -892,6 +946,21 @@ bool IsMonitorOutputSelection(NTV2DeviceID id, IOSelection io)
 	return false;
 }
 
+bool IsIOSelectionSDI(IOSelection io)
+{
+	if (io == IOSelection::SDI1 || io == IOSelection::SDI2 ||
+	    io == IOSelection::SDI3 || io == IOSelection::SDI4 ||
+	    io == IOSelection::SDI5 || io == IOSelection::SDI6 ||
+	    io == IOSelection::SDI7 || io == IOSelection::SDI8 ||
+	    io == IOSelection::SDI1_2 || io == IOSelection::SDI1_2_Squares ||
+	    io == IOSelection::SDI3_4 || io == IOSelection::SDI3_4_Squares ||
+	    io == IOSelection::SDI5_6 || io == IOSelection::SDI7_8 ||
+	    io == IOSelection::SDI1__4 || io == IOSelection::SDI5__8) {
+		return true;
+	}
+	return false;
+}
+
 std::string MakeCardID(CNTV2Card &card)
 {
 	std::string cardID;
@@ -906,4 +975,164 @@ std::string MakeCardID(CNTV2Card &card)
 	return cardID;
 }
 
+RasterDefinition DetermineRasterDefinition(NTV2VideoFormat vf)
+{
+	RasterDefinition def = RasterDefinition::Unknown;
+	if (NTV2_IS_SD_VIDEO_FORMAT(vf)) {
+		def = RasterDefinition::SD;
+	} else if (NTV2_IS_HD_VIDEO_FORMAT(vf)) {
+		def = RasterDefinition::HD;
+	} else if (NTV2_IS_QUAD_FRAME_FORMAT(vf)) {
+		def = RasterDefinition::UHD_4K;
+	} else if (NTV2_IS_QUAD_QUAD_FORMAT(vf)) {
+		def = RasterDefinition::UHD2_8K;
+	} else {
+		def = RasterDefinition::Unknown;
+	}
+	return def;
+}
+
+inline bool IsStandard1080i(NTV2Standard standard)
+{
+	if (standard == NTV2_STANDARD_1080 ||
+	    standard == NTV2_STANDARD_2Kx1080i) {
+		return true;
+	}
+	return false;
+}
+inline bool IsStandard1080p(NTV2Standard standard)
+{
+	if (standard == NTV2_STANDARD_1080p || standard == NTV2_STANDARD_2K ||
+	    standard == NTV2_STANDARD_2Kx1080p) {
+		return true;
+	}
+	return false;
+}
+
+VPIDStandard DetermineVPIDStandard(NTV2DeviceID id, IOSelection io,
+				   NTV2VideoFormat vf, NTV2PixelFormat pf,
+				   SDITransport trx, SDITransport4K t4k)
+{
+	VPIDStandard vpid = VPIDStandard_Unknown;
+	auto rd = aja::DetermineRasterDefinition(vf);
+	auto standard = GetNTV2StandardFromVideoFormat(vf);
+	bool is_rgb = NTV2_IS_FBF_RGB(pf);
+	if (rd == RasterDefinition::SD) {
+		vpid = VPIDStandard_483_576;
+	} else if (rd == RasterDefinition::HD) {
+		vpid = VPIDStandard_1080;
+		if (aja::IsSDIOneWireIOSelection(io)) {
+			if (is_rgb) {
+				if (standard == NTV2_STANDARD_720) {
+					if (trx == SDITransport::SingleLink) {
+						vpid = VPIDStandard_720;
+					} else if (trx ==
+						   SDITransport::SDI3Ga) {
+						vpid = VPIDStandard_720_3Ga;
+					} else if (trx ==
+						   SDITransport::SDI3Gb) {
+						vpid = VPIDStandard_720_3Gb;
+					}
+				} else if (IsStandard1080p(standard)) {
+					if (trx == SDITransport::SingleLink) {
+						vpid = VPIDStandard_1080;
+					} else if (trx ==
+						   SDITransport::SDI3Ga) {
+						vpid = VPIDStandard_1080_3Ga;
+					} else if (trx ==
+						   SDITransport::SDI3Gb) {
+						vpid = VPIDStandard_1080_3Gb;
+					}
+				}
+			} else {
+				if (standard == NTV2_STANDARD_720) {
+					vpid = VPIDStandard_720;
+				} else if (IsStandard1080i(standard)) {
+					vpid = VPIDStandard_1080;
+				} else if (IsStandard1080p(standard) &&
+					   trx == SDITransport::SDI3Ga) {
+					vpid = VPIDStandard_1080_3Ga;
+				} else if (IsStandard1080p(standard) &&
+					   trx == SDITransport::SDI3Gb) {
+					vpid = VPIDStandard_1080_3Gb;
+				}
+			}
+		} else if (aja::IsSDITwoWireIOSelection(io)) {
+			if (is_rgb) {
+				if (standard == NTV2_STANDARD_720) {
+					if (trx == SDITransport::SDI3Ga)
+						vpid = VPIDStandard_720_3Ga;
+					else if (trx == SDITransport::SDI3Gb)
+						vpid = VPIDStandard_720_3Gb;
+				} else if (IsStandard1080p(standard)) {
+					if (trx == SDITransport::SDI3Ga)
+						vpid = VPIDStandard_1080_Dual_3Ga;
+					else if (trx == SDITransport::SDI3Gb)
+						vpid = VPIDStandard_1080_Dual_3Gb;
+				}
+			} else {
+				if (IsStandard1080p(standard) &&
+				    trx == SDITransport::HDDualLink) {
+					vpid = VPIDStandard_1080_DualLink;
+				}
+			}
+		}
+	} else if (rd == RasterDefinition::UHD_4K) {
+		if (aja::IsSDIOneWireIOSelection(io)) {
+			if (is_rgb) {
+				if (trx == SDITransport::SDI6G) {
+					vpid = VPIDStandard_2160_DualLink;
+				} else if (trx == SDITransport::SDI12G) {
+					vpid = VPIDStandard_2160_DualLink_12Gb;
+				}
+			} else {
+				// YCbCr
+				if (trx == SDITransport::SDI6G) {
+					vpid = VPIDStandard_2160_Single_6Gb;
+				} else if (trx == SDITransport::SDI12G) {
+					vpid = VPIDStandard_2160_Single_12Gb;
+				} else {
+					vpid = VPIDStandard_2160_Single_6Gb; // fallback
+				}
+			}
+		} else if (aja::IsSDITwoWireIOSelection(io)) {
+			if (is_rgb) {
+			} else {
+				// YCbCr
+				if (t4k == SDITransport4K::Squares) {
+					vpid = VPIDStandard_1080;
+				} else if (t4k ==
+					   SDITransport4K::TwoSampleInterleave) {
+					vpid = VPIDStandard_2160_DualLink;
+				}
+			}
+		} else if (aja::IsSDIFourWireIOSelection(io)) {
+			if (is_rgb) {
+			} else {
+				// YCbCr
+				if (t4k == SDITransport4K::Squares) {
+					if (trx == SDITransport::SDI3Ga) {
+						vpid = VPIDStandard_1080_3Ga;
+					} else if (trx ==
+						   SDITransport::SDI3Gb) {
+						vpid = VPIDStandard_1080_DualLink_3Gb;
+					} else {
+						vpid = VPIDStandard_1080;
+					}
+				} else if (t4k ==
+					   SDITransport4K::TwoSampleInterleave) {
+					if (trx == SDITransport::SDI3Ga) {
+						vpid = VPIDStandard_2160_QuadLink_3Ga;
+					} else if (trx ==
+						   SDITransport::SDI3Gb) {
+						vpid = VPIDStandard_2160_QuadDualLink_3Gb;
+					}
+				}
+			}
+		}
+	} else if (rd == RasterDefinition::UHD2_8K) {
+	}
+	return vpid;
+}
+
 } // aja

+ 13 - 4
plugins/aja/aja-common.hpp

@@ -17,8 +17,7 @@ using VideoStandardList = std::vector<NTV2Standard>;
 static const uint32_t kDefaultAudioChannels = 8;
 static const uint32_t kDefaultAudioSampleRate = 48000;
 static const uint32_t kDefaultAudioSampleSize = 4;
-static const int kVideoFormatAuto = -1;
-static const int kPixelFormatAuto = -1;
+static const int kAutoDetect = -1;
 static const NTV2PixelFormat kDefaultAJAPixelFormat = NTV2_FBF_8BIT_YCBCR;
 
 // Common OBS property helpers used by both the capture and output plugins
@@ -41,6 +40,7 @@ populate_video_format_list(NTV2DeviceID deviceID, obs_property_t *list,
 			   NTV2VideoFormat genlockFormat = NTV2_FORMAT_UNKNOWN);
 extern void populate_pixel_format_list(NTV2DeviceID deviceID,
 				       obs_property_t *list);
+extern void populate_sdi_transport_list(obs_property_t *list, IOSelection io);
 extern void populate_sdi_4k_transport_list(obs_property_t *list);
 extern bool aja_video_format_changed(obs_properties_t *props,
 				     obs_property_t *list,
@@ -59,6 +59,8 @@ extern video_format AJAPixelFormatToOBSVideoFormat(NTV2PixelFormat pf);
 extern void GetSortedVideoFormats(NTV2DeviceID id,
 				  const VideoStandardList &standards,
 				  VideoFormatList &videoFormats);
+extern NTV2VideoFormat
+HandleSpecialCaseFormats(IOSelection io, NTV2VideoFormat vf, NTV2DeviceID id);
 
 extern uint32_t CardNumFramestores(NTV2DeviceID id);
 extern uint32_t CardNumAudioSystems(NTV2DeviceID id);
@@ -70,10 +72,11 @@ extern NTV2VideoFormat GetLevelAFormatForLevelBFormat(NTV2VideoFormat vf);
 extern NTV2VideoFormat InterlacedFormatForPsfFormat(NTV2VideoFormat vf);
 extern bool IsSingleSDIDevice(NTV2DeviceID id);
 extern bool IsIODevice(NTV2DeviceID id);
-extern bool IsRetailSDI12G(NTV2DeviceID id);
+extern bool IsRetail12GSDICard(NTV2DeviceID id);
 extern bool IsOutputOnlyDevice(NTV2DeviceID id);
 
-extern std::string SDI4KTransportToString(SDI4KTransport mode);
+extern std::string SDITransportToString(SDITransport mode);
+extern std::string SDITransport4KToString(SDITransport4K mode);
 
 extern std::string IOSelectionToString(IOSelection io);
 extern void IOSelectionToInputSources(IOSelection io,
@@ -86,7 +89,13 @@ extern bool IsSDIOneWireIOSelection(IOSelection io);
 extern bool IsSDITwoWireIOSelection(IOSelection io);
 extern bool IsSDIFourWireIOSelection(IOSelection io);
 extern bool IsMonitorOutputSelection(NTV2DeviceID id, IOSelection io);
+extern bool IsIOSelectionSDI(IOSelection io);
 
 extern std::string MakeCardID(CNTV2Card &card);
 
+extern RasterDefinition DetermineRasterDefinition(NTV2VideoFormat vf);
+extern VPIDStandard DetermineVPIDStandard(NTV2DeviceID id, IOSelection io,
+					  NTV2VideoFormat vf,
+					  NTV2PixelFormat pf, SDITransport trx,
+					  SDITransport4K t4k);
 } // aja

+ 35 - 35
plugins/aja/aja-enums.hpp

@@ -1,6 +1,24 @@
 #pragma once
 
-// Additional enums used throughout the AJA plugins for signal routing configuration.
+#include <ajantv2/includes/ntv2vpid.h>
+
+#include <utility>
+
+// Flags corresponding to card register enables
+typedef enum {
+	kEnable3GOut = 1 << 0,
+	kEnable6GOut = 1 << 1,
+	kEnable12GOut = 1 << 2,
+	kConvert3GIn = 1 << 3,
+	kConvert3GOut = 1 << 4,
+	kConvert3GaRGBOut = 1 << 5,
+	kEnable3GbOut = 1 << 6,
+	kEnable4KSquares = 1 << 7,
+	kEnable8KSquares = 1 << 8,
+	kEnable4KTSI = 1 << 9,
+} RoutingPresetFlags;
+
+enum class ConnectionKind { SDI = 0, HDMI = 1, Analog = 2, Unknown };
 
 enum class IOSelection {
 	SDI1 = 0,
@@ -33,44 +51,24 @@ enum class IOSelection {
 	NumIOSelections = Invalid
 };
 
-enum class SDI4KTransport { Squares = 0, TwoSampleInterleave = 1, Unknown = 2 };
+enum class SDITransport {
+	SingleLink = 0, // SD/HD up to 1.5Gbps link
+	HDDualLink = 1, // HD Dual-1.5Gbps Links
+	SDI3Ga = 2,     // 3Gbps Level-A
+	SDI3Gb = 3,     // 3Gbps Level-B
+	SDI6G = 4,      // 6Gbps
+	SDI12G = 5,     // 12Gbps
+	Unknown
+};
+
+enum class SDITransport4K { Squares = 0, TwoSampleInterleave = 1, Unknown = 2 };
 
 enum class RasterDefinition {
 	SD = 0,
 	HD = 1,
 	UHD_4K = 2,
-	UHD_4K_Retail_12G = 3,
-	UHD2_8K = 4,
-	Unknown = 5
-};
-
-enum class SDIWireFormat {
-	SD_ST352 = 0,
-	HD_720p_ST292 = 1,
-	HD_1080_ST292 = 2,
-	HD_1080_ST372_Dual = 3,
-	HD_720p_ST425_3Ga = 4,
-	HD_1080p_ST425_3Ga = 5,
-	HD_1080p_ST425_3Gb_DL = 6,
-	HD_720p_ST425_3Gb = 7,
-	HD_1080p_ST425_3Gb = 8,
-	HD_1080p_ST425_Dual_3Ga = 9,
-	HD_1080p_ST425_Dual_3Gb = 10,
-	UHD4K_ST292_Dual_1_5_Squares = 11,
-	UHD4K_ST292_Quad_1_5_Squares = 12,
-	UHD4K_ST425_Quad_3Ga_Squares = 13,
-	UHD4K_ST425_Quad_3Gb_Squares = 14,
-	UHD4K_ST425_Dual_3Gb_2SI = 15,
-	UHD4K_ST425_Quad_3Ga_2SI = 16,
-	UHD4K_ST425_Quad_3Gb_2SI = 17,
-	UHD4K_ST2018_6G_Squares_2SI = 18,
-	UHD4K_ST2018_6G_Squares_2SI_Kona5_io4KPlus = 19,
-	UHD4K_ST2018_12G_Squares_2SI = 20,
-	UHD4K_ST2018_12G_Squares_2SI_Kona5_io4KPlus = 21,
-	UHD28K_ST2082_Dual_12G = 22,
-	UHD28K_ST2082_RGB_Dual_12G = 23,
-	UHD28K_ST2082_Quad_12G = 24,
-	Unknown = 25,
+	UHD2_8K = 3,
+	Unknown
 };
 
 enum class HDMIWireFormat {
@@ -84,5 +82,7 @@ enum class HDMIWireFormat {
 	UHD_4K_RGB_LFR = 7,
 	UHD_4K_RGB_HFR = 8,
 	TTAP_PRO = 9,
-	Unknown = 10
+	Unknown
 };
+
+using VPIDSpec = std::pair<RasterDefinition, VPIDStandard>;

+ 36 - 97
plugins/aja/aja-output.cpp

@@ -65,7 +65,6 @@ AJAOutput::AJAOutput(CNTV2Card *card, const std::string &cardID,
 	  mOutputID{outputID},
 	  mDeviceIndex{deviceIndex},
 	  mDeviceID{deviceID},
-	  mFrameTimes{},
 	  mAudioPlayCursor{0},
 	  mAudioWriteCursor{0},
 	  mAudioWrapAddress{0},
@@ -140,31 +139,17 @@ void AJAOutput::Initialize(const OutputProps &props)
 				     props.pixelFormat);
 
 	mCard->SetOutputFrame(props.Channel(), mWriteCardFrame);
-
 	mCard->WaitForOutputVerticalInterrupt(props.Channel());
-
 	const auto &cardFrameRate =
 		GetNTV2FrameRateFromVideoFormat(props.videoFormat);
-
 	ULWord fpsNum = 0;
 	ULWord fpsDen = 0;
 	GetFramesPerSecond(cardFrameRate, fpsNum, fpsDen);
 	mFrameRateNum = fpsNum;
 	mFrameRateDen = fpsDen;
-	mFrameTimes.cardFrameTime =
-		(1000000000ULL / (uint64_t)(fpsNum / fpsDen));
-	mFrameTimes.cardFps = (double)(fpsNum / fpsDen);
-	mFrameTimes.obsFps = obs_get_active_fps();
-	if (mFrameTimes.obsFps < 1.0)
-		mFrameTimes.obsFps = 30.0;
-	mFrameTimes.obsFrameTime =
-		(1000000000ULL / (uint64_t)mFrameTimes.obsFps);
-
 	mVideoDelay = ((int64_t)mNumCardFrames - 0) * 1000000 * mFrameRateDen /
 		      mFrameRateNum;
-
 	mAudioRate = props.audioSampleRate;
-
 	SetOutputProps(props);
 }
 
@@ -510,7 +495,7 @@ uint32_t AJAOutput::get_frame_count()
 }
 
 // Perform DMA of audio samples to AJA card while taking into account wrapping around the
-// ends of the card's audio buffer (size set to 4MB in Routing::ConfigureOutputAudio).
+// ends of the card's audio buffer (size set to 4MB in aja::Routing::ConfigureOutputAudio).
 void AJAOutput::dma_audio_samples(NTV2AudioSystem audioSys, uint32_t *data,
 				  size_t size)
 {
@@ -780,28 +765,8 @@ bool aja_output_device_changed(void *data, obs_properties_t *props,
 	populate_output_device_list(list);
 
 	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
-
-	size_t itemCount = obs_property_list_item_count(list);
-	bool itemFound = false;
-
-	for (size_t i = 0; i < itemCount; i++) {
-		const char *itemCardID = obs_property_list_item_string(list, i);
-		if (strcmp(cardID, itemCardID) == 0) {
-			itemFound = true;
-			break;
-		}
-	}
-
-	if (!itemFound) {
-		obs_property_list_insert_string(list, 0, cardID, cardID);
-		obs_property_list_item_disable(list, 0, true);
-		return true;
-	}
-
-	if (!cardID) {
-		blog(LOG_ERROR, "aja_output_device_changed: Card ID is null!");
+	if (!cardID)
 		return false;
-	}
 
 	const char *outputID =
 		obs_data_get_string(settings, kUIPropAJAOutputID.id);
@@ -828,8 +793,10 @@ bool aja_output_device_changed(void *data, obs_properties_t *props,
 		obs_properties_get(props, kUIPropVideoFormatSelect.id);
 	obs_property_t *pix_fmt_list =
 		obs_properties_get(props, kUIPropPixelFormatSelect.id);
+	obs_property_t *sdi_trx_list =
+		obs_properties_get(props, kUIPropSDITransport.id);
 	obs_property_t *sdi_4k_list =
-		obs_properties_get(props, kUIPropSDI4KTransport.id);
+		obs_properties_get(props, kUIPropSDITransport4K.id);
 
 	const NTV2DeviceID deviceID = cardEntry->GetDeviceID();
 	populate_io_selection_output_list(cardID, outputID, deviceID,
@@ -850,6 +817,11 @@ bool aja_output_device_changed(void *data, obs_properties_t *props,
 	obs_property_list_clear(pix_fmt_list);
 	populate_pixel_format_list(deviceID, pix_fmt_list);
 
+	IOSelection io_select = static_cast<IOSelection>(
+		obs_data_get_int(settings, kUIPropOutput.id));
+	obs_property_list_clear(sdi_trx_list);
+	populate_sdi_transport_list(sdi_trx_list, io_select);
+
 	obs_property_list_clear(sdi_4k_list);
 	populate_sdi_4k_transport_list(sdi_4k_list);
 
@@ -863,11 +835,9 @@ bool aja_output_dest_changed(obs_properties_t *props, obs_property_t *list,
 
 	blog(LOG_DEBUG, "AJA Output Dest Changed");
 
+	bool itemFound = false;
 	int dest = obs_data_get_int(settings, kUIPropOutput.id);
-
 	size_t itemCount = obs_property_list_item_count(list);
-	bool itemFound = false;
-
 	for (size_t i = 0; i < itemCount; i++) {
 		int itemDest = obs_property_list_item_int(list, i);
 		if (dest == itemDest) {
@@ -875,29 +845,12 @@ bool aja_output_dest_changed(obs_properties_t *props, obs_property_t *list,
 			break;
 		}
 	}
-
 	if (!itemFound) {
 		obs_property_list_insert_int(list, 0, "", dest);
 		obs_property_list_item_disable(list, 0, true);
 		return true;
 	}
 
-	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
-	if (!cardID) {
-		blog(LOG_ERROR, "aja_output_dest_changed: Card ID is null!");
-		return false;
-	}
-
-	auto &cardManager = aja::CardManager::Instance();
-	cardManager.EnumerateCards();
-	auto cardEntry = cardManager.GetCardEntry(cardID);
-	if (!cardEntry) {
-		blog(LOG_ERROR,
-		     "aja_output_dest_changed: Card entry not found for %s",
-		     cardID);
-		return false;
-	}
-
 	// Revert to "Select..." if desired IOSelection is already in use
 	auto io_select = static_cast<IOSelection>(
 		obs_data_get_int(settings, kUIPropOutput.id));
@@ -916,6 +869,13 @@ bool aja_output_dest_changed(obs_properties_t *props, obs_property_t *list,
 		}
 	}
 
+	obs_property_t *sdi_trx_list =
+		obs_properties_get(props, kUIPropSDITransport.id);
+	obs_property_list_clear(sdi_trx_list);
+	populate_sdi_transport_list(sdi_trx_list, io_select);
+	obs_property_set_visible(sdi_trx_list,
+				 aja::IsIOSelectionSDI(io_select));
+
 	return true;
 }
 
@@ -971,7 +931,6 @@ static void *aja_output_create(obs_data_t *settings, obs_output_t *output)
 	}
 
 	NTV2DeviceID deviceID = card->GetDeviceID();
-
 	OutputProps outputProps(deviceID);
 	outputProps.ioSelect = static_cast<IOSelection>(
 		obs_data_get_int(settings, kUIPropOutput.id));
@@ -980,20 +939,19 @@ static void *aja_output_create(obs_data_t *settings, obs_output_t *output)
 		     "aja_output_create: Select a valid AJA Output IOSelection!");
 		return nullptr;
 	}
-
 	outputProps.videoFormat = static_cast<NTV2VideoFormat>(
 		obs_data_get_int(settings, kUIPropVideoFormatSelect.id));
 	outputProps.pixelFormat = static_cast<NTV2PixelFormat>(
 		obs_data_get_int(settings, kUIPropPixelFormatSelect.id));
-	outputProps.sdi4kTransport = static_cast<SDI4KTransport>(
-		obs_data_get_int(settings, kUIPropSDI4KTransport.id));
-
+	outputProps.sdiTransport = static_cast<SDITransport>(
+		obs_data_get_int(settings, kUIPropSDITransport.id));
+	outputProps.sdi4kTransport = static_cast<SDITransport4K>(
+		obs_data_get_int(settings, kUIPropSDITransport4K.id));
 	outputProps.audioNumChannels = kDefaultAudioChannels;
 	outputProps.audioSampleSize = kDefaultAudioSampleSize;
 	outputProps.audioSampleRate = kDefaultAudioSampleRate;
-
 	if (NTV2_IS_4K_VIDEO_FORMAT(outputProps.videoFormat) &&
-	    outputProps.sdi4kTransport == SDI4KTransport::Squares) {
+	    outputProps.sdi4kTransport == SDITransport4K::Squares) {
 		if (outputProps.ioSelect == IOSelection::SDI1_2) {
 			outputProps.ioSelect = IOSelection::SDI1_2_Squares;
 		} else if (outputProps.ioSelect == IOSelection::SDI3_4) {
@@ -1025,7 +983,6 @@ static void *aja_output_create(obs_data_t *settings, obs_output_t *output)
 	auto ajaOutput = new AJAOutput(card, cardID, outputID,
 				       (UWord)cardEntry->GetCardIndex(),
 				       deviceID);
-
 	ajaOutput->Initialize(outputProps);
 	ajaOutput->ClearVideoQueue();
 	ajaOutput->ClearAudioQueue();
@@ -1066,9 +1023,7 @@ static bool aja_output_start(void *data)
 
 	const std::string &cardID = ajaOutput->mCardID;
 	auto &cardManager = aja::CardManager::Instance();
-
 	cardManager.EnumerateCards();
-
 	auto cardEntry = cardManager.GetCardEntry(cardID);
 	if (!cardEntry) {
 		blog(LOG_DEBUG,
@@ -1115,14 +1070,14 @@ static bool aja_output_start(void *data)
 	}
 
 	// Configures crosspoint routing on AJA card
-	if (!Routing::ConfigureOutputRoute(outputProps, NTV2_MODE_DISPLAY,
-					   card)) {
+	if (!aja::Routing::ConfigureOutputRoute(outputProps, NTV2_MODE_DISPLAY,
+						card)) {
 		blog(LOG_ERROR,
 		     "aja_output_start: Error configuring output route!");
 		return false;
 	}
 
-	Routing::ConfigureOutputAudio(outputProps, card);
+	aja::Routing::ConfigureOutputAudio(outputProps, card);
 
 	const auto &formatDesc = outputProps.FormatDesc();
 	struct video_scale_info scaler = {};
@@ -1166,26 +1121,22 @@ static void aja_output_stop(void *data, uint64_t ts)
 		blog(LOG_ERROR, "aja_output_stop: Plugin instance is null!");
 		return;
 	}
-
-	auto outputProps = ajaOutput->GetOutputProps();
 	const std::string &cardID = ajaOutput->mCardID;
 	auto &cardManager = aja::CardManager::Instance();
-
 	cardManager.EnumerateCards();
-
 	auto cardEntry = cardManager.GetCardEntry(cardID);
 	if (!cardEntry) {
 		blog(LOG_ERROR, "aja_output_stop: Card Entry not found for %s",
 		     cardID.c_str());
 		return;
 	}
-
 	CNTV2Card *card = ajaOutput->GetCard();
 	if (!card) {
 		blog(LOG_ERROR, "aja_output_stop: Card instance is null!");
 		return;
 	}
 
+	auto outputProps = ajaOutput->GetOutputProps();
 	if (!cardEntry->ReleaseOutputSelection(outputProps.ioSelect,
 					       card->GetDeviceID(),
 					       ajaOutput->mOutputID)) {
@@ -1194,15 +1145,13 @@ static void aja_output_stop(void *data, uint64_t ts)
 		     aja::IOSelectionToString(outputProps.ioSelect).c_str(),
 		     cardID.c_str());
 	}
-
-	auto audioSystem = outputProps.AudioSystem();
-
 	ajaOutput->GenerateTestPattern(outputProps.videoFormat,
 				       outputProps.pixelFormat,
 				       NTV2_TestPatt_Black);
 
 	obs_output_end_data_capture(ajaOutput->GetOBSOutput());
 
+	auto audioSystem = outputProps.AudioSystem();
 	card->StopAudioOutput(audioSystem);
 
 	blog(LOG_INFO, "AJA Output stopped.");
@@ -1234,28 +1183,28 @@ static void aja_output_raw_audio(void *data, struct audio_data *frames)
 static obs_properties_t *aja_output_get_properties(void *data)
 {
 	obs_properties_t *props = obs_properties_create();
-
 	obs_property_t *device_list = obs_properties_add_list(
 		props, kUIPropDevice.id, obs_module_text(kUIPropDevice.text),
 		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
-
 	obs_property_t *output_list = obs_properties_add_list(
 		props, kUIPropOutput.id, obs_module_text(kUIPropOutput.text),
 		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
 	obs_property_t *vid_fmt_list = obs_properties_add_list(
 		props, kUIPropVideoFormatSelect.id,
 		obs_module_text(kUIPropVideoFormatSelect.text),
 		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
 	obs_properties_add_list(props, kUIPropPixelFormatSelect.id,
 				obs_module_text(kUIPropPixelFormatSelect.text),
 				OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
-	obs_properties_add_list(props, kUIPropSDI4KTransport.id,
-				obs_module_text(kUIPropSDI4KTransport.text),
+	obs_properties_add_list(props, kUIPropSDITransport.id,
+				obs_module_text(kUIPropSDITransport.text),
+				OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
+	obs_properties_add_list(props, kUIPropSDITransport.id,
+				obs_module_text(kUIPropSDITransport.text),
+				OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
+	obs_properties_add_list(props, kUIPropSDITransport4K.id,
+				obs_module_text(kUIPropSDITransport4K.text),
 				OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
 	obs_properties_add_bool(props, kUIPropAutoStartOutput.id,
 				obs_module_text(kUIPropAutoStartOutput.text));
 
@@ -1265,7 +1214,6 @@ static obs_properties_t *aja_output_get_properties(void *data)
 					   aja_output_dest_changed);
 	obs_property_set_modified_callback2(device_list,
 					    aja_output_device_changed, data);
-
 	return props;
 }
 
@@ -1274,13 +1222,6 @@ static const char *aja_output_get_name(void *)
 	return obs_module_text(kUIPropOutputModule.text);
 }
 
-// NOTE(paulh): Drop-down defaults are set on a clean launch in aja-output-ui code.
-// Otherwise we load the settings stored in the ajaOutputProps/ajaPreviewOutputProps.json configs.
-void aja_output_get_defaults(obs_data_t *settings)
-{
-	obs_data_set_default_bool(settings, kUIPropAutoStartOutput.id, false);
-}
-
 struct obs_output_info create_aja_output_info()
 {
 	struct obs_output_info aja_output_info = {};
@@ -1295,8 +1236,6 @@ struct obs_output_info create_aja_output_info()
 	aja_output_info.raw_video = aja_output_raw_video;
 	aja_output_info.raw_audio = aja_output_raw_audio;
 	aja_output_info.update = aja_output_update;
-	aja_output_info.get_defaults = aja_output_get_defaults;
 	aja_output_info.get_properties = aja_output_get_properties;
-
 	return aja_output_info;
 }

+ 0 - 10
plugins/aja/aja-output.hpp

@@ -28,14 +28,6 @@ struct AudioFrames {
 	size_t size;
 };
 
-//TODO(paulh): Refactor me into OutputProps
-struct FrameTimes {
-	double obsFps;
-	uint64_t obsFrameTime;
-	double cardFps;
-	uint64_t cardFrameTime;
-};
-
 using VideoQueue = std::deque<VideoFrame>;
 using AudioQueue = std::deque<AudioFrames>;
 
@@ -90,8 +82,6 @@ public:
 	UWord mDeviceIndex;
 	NTV2DeviceID mDeviceID;
 
-	FrameTimes mFrameTimes;
-
 	uint32_t mAudioPlayCursor;
 	uint32_t mAudioWriteCursor;
 	uint32_t mAudioWrapAddress;

+ 1544 - 0
plugins/aja/aja-presets.cpp

@@ -0,0 +1,1544 @@
+#include "aja-common.hpp"
+#include "aja-presets.hpp"
+
+#include <ajantv2/includes/ntv2devicefeatures.h>
+#include <ajantv2/includes/ntv2utils.h>
+
+namespace aja {
+
+RoutingConfigurator::RoutingConfigurator()
+{
+	build_preset_table();
+}
+
+void RoutingConfigurator::AddPreset(const std::string &name,
+				    const RoutingPreset &preset)
+{
+	if (m_presets.find(name) != m_presets.end())
+		return;
+	m_presets.insert(RoutingPresetPair{name, preset});
+}
+
+bool RoutingConfigurator::PresetByName(const std::string &name,
+				       RoutingPreset &preset) const
+{
+	if (m_presets.find(name) != m_presets.end()) {
+		preset = m_presets.at(name);
+		return true;
+	}
+	return false;
+}
+
+void RoutingConfigurator::build_preset_table()
+{
+	static const RoutingPresetMap kRoutingPresets = {
+		/*
+        * HDMI RGB Capture
+        */
+		{"HDMI_HD_RGB_LFR_RGB_Capture",
+		 {"HDMI_HD_RGB_LFR_RGB_Capture",
+		  ConnectionKind::HDMI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "hdmi[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::HD_RGB_LFR,
+		  VPIDStandard_Unknown}},
+		/*
+        * HDMI RGB Display
+        */
+		{"HDMI_HD_RGB_LFR_RGB_Display",
+		 {"HDMI_HD_RGB_LFR_RGB_Display",
+		  ConnectionKind::HDMI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "fb[{ch1}][0]->hdmi[0][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::HD_RGB_LFR,
+		  VPIDStandard_Unknown}},
+		{"HDMI_HD_RGB_LFR_RGB_Display (TTap Pro)",
+		 {"HDMI_HD_RGB_LFR_RGB_Display (TTap Pro)",
+		  ConnectionKind::HDMI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch1}][0]->hdmi[{ch1}][0];",
+		  {DEVICE_ID_TTAP_PRO},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::HD_RGB_LFR,
+		  VPIDStandard_Unknown}},
+		/*
+        * HDMI YCbCr Capture
+        */
+		{"HDMI_HD_YCBCR_LFR_YCbCr_Capture",
+		 {"HDMI_HD_YCBCR_LFR_YCbCr_Capture",
+		  ConnectionKind::HDMI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "hdmi[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::HD_YCBCR_LFR,
+		  VPIDStandard_Unknown}},
+		/*
+        * HDMI YCbCr Display
+        */
+		{"HDMI_HD_YCBCR_LFR_YCbCr_Display",
+		 {"HDMI_HD_YCBCR_LFR_YCbCr_Display",
+		  ConnectionKind::HDMI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "fb[{ch1}][0]->hdmi[0][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::HD_YCBCR_LFR,
+		  VPIDStandard_Unknown}},
+		{"HDMI_HD_YCBCR_LFR_YCbCr_Display (TTap Pro)",
+		 {"HDMI_HD_YCBCR_LFR_YCbCr_Display (TTap Pro)",
+		  ConnectionKind::HDMI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch1}][0]->hdmi[{ch1}][0];",
+		  {DEVICE_ID_TTAP_PRO},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::HD_YCBCR_LFR,
+		  VPIDStandard_Unknown}},
+		/*
+        * SDI RGB Capture
+        */
+		// { "SD_ST352_RGB_Capture", {
+		//     "SD_ST352_RGB_Capture",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_CAPTURE,
+		//     1, 1,
+		//     0,
+		//     true,
+		//     "", {},
+		//     RasterDefinition::SD,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_483_576
+		// } }, // NOTE(paulh): SD RGB not a valid capture config
+		{"HD_720p_ST292_RGB_Capture",
+		 {"HD_720p_ST292_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720}},
+		{"HD_1080_ST292_RGB_Capture",
+		 {"HD_1080_ST292_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080}},
+		{"HD_1080_ST372_Dual_RGB_Capture",
+		 {"HD_1080_ST372_Dual_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  1,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch2}][0]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink}},
+		{"HD_720p_ST425_3Ga_RGB_Capture",
+		 {"HD_720p_ST425_3Ga_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Ga}},
+		{"HD_1080p_ST425_3Ga_RGB_Capture",
+		 {"HD_1080p_ST425_3Ga_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Ga}},
+		{"HD_1080p_ST425_3Gb_DL_RGB_Capture",
+		 {"HD_1080p_ST425_3Gb_DL_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink_3Gb}},
+		{"HD_720p_ST425_3Gb_RGB_Capture",
+		 {"HD_720p_ST425_3Gb_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  2,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Gb}},
+		{"HD_1080p_ST425_3Gb_RGB_Capture",
+		 {"HD_1080p_ST425_3Gb_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  2,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Gb}},
+		{"HD_1080p_ST425_Dual_3Ga_RGB_Capture",
+		 {"HD_1080p_ST425_Dual_3Ga_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  2,
+		  0,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "sdi[{ch2}][0]->dli[{ch2}][0];"
+		  "sdi[{ch2}][1]->dli[{ch2}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];"
+		  "dli[{ch2}][0]->fb[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_Dual_3Ga}},
+		{"HD_1080p_ST425_Dual_3Gb_RGB_Capture",
+		 {"HD_1080p_ST425_Dual_3Gb_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  2,
+		  kConvert3GIn,
+		  true,
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "sdi[{ch2}][0]->dli[{ch2}][0];"
+		  "sdi[{ch2}][1]->dli[{ch2}][1];"
+		  "dli[{ch1}][0]->fb[{ch1}][0];"
+		  "dli[{ch2}][0]->fb[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_Dual_3Gb}},
+		// { "UHD4K_ST292_Quad_1_5_Squares_RGB_Capture", {
+		//     "UHD4K_ST292_Quad_1_5_Squares_RGB_Capture",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_CAPTURE,
+		//     4, 4,
+		//     0,
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_1080
+		// } }, // NOTE(paulh): Not a valid RGB capture config
+		// { "UHD4K_ST425_Quad_3Ga_Squares_RGB_Capture", {
+		//     "UHD4K_ST425_Quad_3Ga_Squares_RGB_Capture",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_CAPTURE,
+		//     4, 4,
+		//     0,
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_1080_3Ga
+		// } }, // NOTE(paulh): Not a valid RGB capture config
+		{"UHD4K_ST425_Quad_3Gb_Squares_RGB_Capture",
+		 {
+			 "UHD4K_ST425_Quad_3Gb_Squares_RGB_Capture",
+			 ConnectionKind::SDI,
+			 NTV2_MODE_CAPTURE,
+			 4,
+			 4,
+			 kEnable4KSquares,
+			 true,
+			 // SDIs -> Dual-Links
+			 "sdi[{ch1}][0]->dli[{ch1}][0];"
+			 "sdi[{ch1}][1]->dli[{ch1}][1];"
+			 "sdi[{ch2}][0]->dli[{ch2}][0];"
+			 "sdi[{ch2}][1]->dli[{ch2}][1];"
+			 "sdi[{ch3}][0]->dli[{ch3}][0];"
+			 "sdi[{ch3}][1]->dli[{ch3}][1];"
+			 "sdi[{ch4}][0]->dli[{ch4}][0];"
+			 "sdi[{ch4}][1]->dli[{ch4}][1];" // Dual-Links -> Framestores
+			 "dli[{ch1}][0]->fb[{ch1}][2];"
+			 "dli[{ch2}][0]->fb[{ch2}][2];"
+			 "dli[{ch3}][0]->fb[{ch3}][2];"
+			 "dli[{ch4}][0]->fb[{ch4}][2];",
+			 {},
+			 RasterDefinition::UHD_4K,
+			 HDMIWireFormat::Unknown,
+			 VPIDStandard_1080_DualLink_3Gb,
+		 }},
+		// { "UHD4K_ST425_Dual_3Gb_2SI_RGB_Capture", {
+		//     "UHD4K_ST425_Dual_3Gb_2SI_RGB_Capture",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_CAPTURE,
+		//     2, 4,
+		//     (kEnable3GOut | kEnable3GbOut),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_2160_DualLink
+		// } }, // NOTE(paulh): Not a valid RGB capture config
+		{"UHD4K_ST425_Quad_3Ga_2SI_RGB_Capture",
+		 {"UHD4K_ST425_Quad_3Ga_2SI_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable4KTSI),
+		  true,
+		  // SDIs -> Dual-Links
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "sdi[{ch2}][0]->dli[{ch2}][0];"
+		  "sdi[{ch2}][1]->dli[{ch2}][1];"
+		  "sdi[{ch3}][0]->dli[{ch3}][0];"
+		  "sdi[{ch3}][1]->dli[{ch3}][1];"
+		  "sdi[{ch4}][0]->dli[{ch4}][0];"
+		  "sdi[{ch4}][1]->dli[{ch4}][1];" // Dual-Links -> TSI Mux
+		  "dli[{ch1}][0]->tsi[{ch1}][0];"
+		  "dli[{ch2}][0]->tsi[{ch1}][1];"
+		  "dli[{ch3}][0]->tsi[{ch2}][0];"
+		  "dli[{ch4}][0]->tsi[{ch2}][1];" // TSI Mux -> Framestores
+		  "tsi[{ch1}][0]->fb[{ch1}][0];"
+		  "tsi[{ch1}][1]->fb[{ch1}][1];"
+		  "tsi[{ch2}][0]->fb[{ch2}][0];"
+		  "tsi[{ch2}][1]->fb[{ch2}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadLink_3Ga}},
+		{"UHD4K_ST425_Quad_3Gb_2SI_RGB_Capture",
+		 {"UHD4K_ST425_Quad_3Gb_2SI_RGB_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable3GbOut | kEnable4KTSI),
+		  true,
+		  // SDIs -> Dual-Links
+		  "sdi[{ch1}][0]->dli[{ch1}][0];"
+		  "sdi[{ch1}][1]->dli[{ch1}][1];"
+		  "sdi[{ch2}][0]->dli[{ch2}][0];"
+		  "sdi[{ch2}][1]->dli[{ch2}][1];"
+		  "sdi[{ch3}][0]->dli[{ch3}][0];"
+		  "sdi[{ch3}][1]->dli[{ch3}][1];"
+		  "sdi[{ch4}][0]->dli[{ch4}][0];"
+		  "sdi[{ch4}][1]->dli[{ch4}][1];" // Dual-Links -> TSI Mux
+		  "dli[{ch1}][0]->tsi[{ch1}][0];"
+		  "dli[{ch2}][0]->tsi[{ch1}][1];"
+		  "dli[{ch3}][0]->tsi[{ch2}][0];"
+		  "dli[{ch4}][0]->tsi[{ch2}][1];" // TSI Mux -> Framestores
+		  "tsi[{ch1}][0]->fb[{ch1}][0];"
+		  "tsi[{ch1}][1]->fb[{ch1}][1];"
+		  "tsi[{ch2}][0]->fb[{ch2}][0];"
+		  "tsi[{ch2}][1]->fb[{ch2}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadDualLink_3Gb}},
+		// { "UHD4K_ST2018_6G_Squares_2SI_RGB_Capture", {
+		//     "UHD4K_ST2018_6G_Squares_2SI_RGB_Capture",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_CAPTURE,
+		//     2, 2,
+		//     kEnable6GOut,
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_2160_Single_6Gb
+		// } }, // TODO(paulh)
+		/*
+        * SDI RGB Display
+        */
+		// { "SD_ST352_RGB_Display", {
+		//     "SD_ST352_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     1, 1,
+		//     0,
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::SD,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_483_576
+		// } }, // NOTE(paulh): Not a valid RGB display config
+		{"HD_720p_ST292_RGB_Display",
+		 {"HD_720p_ST292_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}[0];"
+		  "dlo[{ch1}][1]->sdi[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720}},
+		{"HD_1080_ST292_RGB_Display",
+		 {"HD_1080_ST292_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}[0];"
+		  "dlo[{ch1}][1]->sdi[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080}},
+		{"HD_1080_ST372_Dual_RGB_Display",
+		 {"HD_1080_ST372_Dual_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  2,
+		  1,
+		  0,
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}[0];"
+		  "dlo[{ch1}][1]->sdi[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink}},
+		{"HD_720p_ST425_3Ga_RGB_Display",
+		 {"HD_720p_ST425_3Ga_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  (kEnable3GOut | kConvert3GaRGBOut),
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Ga}},
+		{"HD_1080p_ST425_3Ga_RGB_Display",
+		 {"HD_1080p_ST425_3Ga_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  (kEnable3GOut | kConvert3GaRGBOut),
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Ga}},
+		{"HD_1080p_ST425_3Gb_DL_RGB_Display",
+		 {"HD_1080p_ST425_3Gb_DL_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  (kEnable3GOut | kEnable3GbOut),
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink_3Gb}},
+		{"HD_720p_ST425_3Gb_RGB_Display",
+		 {"HD_720p_ST425_3Gb_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  2,
+		  (kEnable3GOut | kEnable3GbOut),
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Gb}},
+		{"HD_1080p_ST425_3Gb_RGB_Display",
+		 {"HD_1080p_ST425_3Gb_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  2,
+		  (kEnable3GOut | kEnable3GbOut),
+		  true,
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Gb}},
+		// { "HD_1080p_ST425_Dual_3Ga_RGB_Display", {
+		//     "HD_1080p_ST425_Dual_3Ga_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 2,
+		//     kEnable3GOut,
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::HD,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_1080_Dual_3Ga
+		// } },
+		// { "HD_1080p_ST425_Dual_3Gb_RGB_Display", {
+		//     "HD_1080p_ST425_Dual_3Gb_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 2,
+		//     (kEnable3GOut | kEnable3GbOut),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::HD,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_1080_Dual_3Gb
+		// } },
+		// { "UHD4K_ST292_Quad_1_5_Squares_RGB_Display", {
+		//     "UHD4K_ST292_Quad_1_5_Squares_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     4, 4,
+		//     kEnable4KSquares,
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_1080
+		// } },
+		// { "UHD4K_ST425_Quad_3Ga_Squares_RGB_Display", {
+		//     "UHD4K_ST425_Quad_3Ga_Squares_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     4, 4,
+		//     (kEnable3GOut | kEnable4KSquares),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_1080_3Ga
+		// } },
+		{"UHD4K_ST425_Quad_3Gb_Squares_RGB_Display",
+		 {"UHD4K_ST425_Quad_3Gb_Squares_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable3GbOut | kEnable4KSquares),
+		  true,
+		  // Framestores -> Dual-Links
+		  "fb[{ch1}][2]->dlo[{ch1}][0];"
+		  "fb[{ch2}][2]->dlo[{ch2}][0];"
+		  "fb[{ch3}][2]->dlo[{ch3}][0];"
+		  "fb[{ch4}][2]->dlo[{ch4}][0];" // Dual-Links -> SDIs
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];"
+		  "dlo[{ch2}][0]->sdi[{ch2}][0];"
+		  "dlo[{ch2}][1]->sdi[{ch2}][1];"
+		  "dlo[{ch3}][0]->sdi[{ch3}][0];"
+		  "dlo[{ch3}][1]->sdi[{ch3}][1];"
+		  "dlo[{ch4}][0]->sdi[{ch4}][0];"
+		  "dlo[{ch4}][1]->sdi[{ch4}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink_3Gb}},
+		// { "UHD4K_ST425_Dual_3Gb_2SI_RGB_Display", {
+		//     "UHD4K_ST425_Dual_3Gb_2SI_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 4,
+		//     (kEnable3GOut | kEnable3GbOut | kEnable4KSquares),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_2160_DualLink
+		// } },
+		{"UHD4K_ST425_Quad_3Ga_2SI_RGB_Display",
+		 {"UHD4K_ST425_Quad_3Ga_2SI_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable4KTSI),
+		  true,
+		  "fb[{ch1}][2]->tsi[{ch1}][0];"
+		  "fb[{ch1}][3]->tsi[{ch1}][1];"
+
+		  "fb[{ch2}][2]->tsi[{ch2}][0];"
+		  "fb[{ch2}][3]->tsi[{ch2}][1];"
+
+		  "tsi[{ch1}][2]->dlo[{ch1}][0];"
+		  "tsi[{ch1}][3]->dlo[{ch2}][0];"
+		  "tsi[{ch2}][2]->dlo[{ch3}][0];"
+		  "tsi[{ch2}][3]->dlo[{ch4}][0];"
+
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];"
+		  "dlo[{ch2}][0]->sdi[{ch2}][0];"
+		  "dlo[{ch2}][1]->sdi[{ch2}][1];"
+		  "dlo[{ch3}][0]->sdi[{ch3}][0];"
+		  "dlo[{ch3}][1]->sdi[{ch3}][1];"
+		  "dlo[{ch4}][0]->sdi[{ch4}][0];"
+		  "dlo[{ch4}][1]->sdi[{ch4}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadLink_3Ga}},
+		{"UHD4K_ST425_Quad_3Gb_2SI_RGB_Display",
+		 {"UHD4K_ST425_Quad_3Gb_2SI_RGB_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable4KTSI),
+		  true,
+		  "fb[{ch1}][2]->tsi[{ch1}][0];"
+		  "fb[{ch1}][3]->tsi[{ch1}][1];"
+
+		  "fb[{ch2}][2]->tsi[{ch2}][0];"
+		  "fb[{ch2}][3]->tsi[{ch2}][1];"
+
+		  "tsi[{ch1}][2]->dlo[{ch1}][0];"
+		  "tsi[{ch1}][3]->dlo[{ch2}][0];"
+		  "tsi[{ch2}][2]->dlo[{ch3}][0];"
+		  "tsi[{ch2}][3]->dlo[{ch4}][0];"
+
+		  "dlo[{ch1}][0]->sdi[{ch1}][0];"
+		  "dlo[{ch1}][1]->sdi[{ch1}][1];"
+		  "dlo[{ch2}][0]->sdi[{ch2}][0];"
+		  "dlo[{ch2}][1]->sdi[{ch2}][1];"
+		  "dlo[{ch3}][0]->sdi[{ch3}][0];"
+		  "dlo[{ch3}][1]->sdi[{ch3}][1];"
+		  "dlo[{ch4}][0]->sdi[{ch4}][0];"
+		  "dlo[{ch4}][1]->sdi[{ch4}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadDualLink_3Gb}},
+		// { "UHD4K_ST2018_6G_Squares_2SI_RGB_Display", {
+		//     "UHD4K_ST2018_6G_Squares_2SI_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 4,
+		//     (kEnable6GOut | kEnable4KTSI),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_2160_Single_6Gb
+		// } }, // TODO(paulh)
+		// { "UHD4K_ST2018_12G_Squares_2SI_RGB_Display", {
+		//     "UHD4K_ST2018_12G_Squares_2SI_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 4,
+		//     (kEnable12GOut | kEnable4KTSI),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_2160_Single_12Gb
+		// } }, // TODO(paulh)
+		// { "UHD28K_ST2082_Dual_12G_RGB_Display", {
+		//     "UHD28K_ST2082_Dual_12G_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 4,
+		//     (kEnable12GOut | kEnable4KTSI),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_4320_DualLink_12Gb
+		// } }, // TODO(paulh)
+		// { "UHD28K_ST2082_RGB_Dual_12G_RGB_Display", {
+		//     "UHD28K_ST2082_RGB_Dual_12G_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 4,
+		//     (kEnable12GOut | kEnable4KTSI),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_2160_DualLink_12Gb
+		// } }, // TODO(paulh)
+		// { "UHD28K_ST2082_Quad_12G_RGB_Display", {
+		//     "UHD28K_ST2082_Quad_12G_RGB_Display",
+		//     ConnectionKind::SDI,
+		//     NTV2_MODE_DISPLAY,
+		//     2, 4,
+		//     (kEnable12GOut | kEnable4KTSI),
+		//     true,
+		//     "",
+		//     {},
+		//     RasterDefinition::UHD_4K,
+		//     HDMIWireFormat::Unknown,
+		//     VPIDStandard_4320_QuadLink_12Gb
+		// } }, // TODO(paulh)
+		// ################################################################
+		// SDI YCbCr Capture
+		// ################################################################
+		{"SD_ST352_YCbCr_Capture",
+		 {"SD_ST352_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0]",
+		  {},
+		  RasterDefinition::SD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_483_576}},
+		{"HD_720p_ST292_YCbCr_Capture",
+		 {"HD_720p_ST292_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0]",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720}},
+		{"HD_1080_ST292_YCbCr_Capture",
+		 {"HD_1080_ST292_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0]",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080}},
+		{"HD_1080_ST372_Dual_YCbCr_Capture",
+		 {"HD_1080_ST372_Dual_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  2,
+		  0,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch2}][0]->fb[{ch2}][0]",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink}},
+		{"HD_720p_ST425_3Ga_YCbCr_Capture",
+		 {"HD_720p_ST425_3Ga_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  kEnable3GOut,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0]",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Ga}},
+		{"HD_1080p_ST425_3Ga_YCbCr_Capture",
+		 {"HD_1080p_ST425_3Ga_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  kEnable3GOut,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0]",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Ga}},
+		{"HD_1080p_ST425_3Gb_DL_YCbCr_Capture",
+		 {"HD_1080p_ST425_3Gb_DL_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  (kEnable3GOut | kConvert3GIn | kConvert3GOut),
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0]",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink_3Gb}},
+		{"HD_720p_ST425_3Gb_YCbCr_Capture",
+		 {"HD_720p_ST425_3Gb_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  2,
+		  kEnable3GOut,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch1}][1]->fb[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Gb}},
+		{"HD_1080p_ST425_3Gb_YCbCr_Capture",
+		 {"HD_1080p_ST425_3Gb_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  2,
+		  kEnable3GOut,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch1}][1]->fb[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Gb}},
+		{"HD_1080p_ST425_Dual_3Ga_YCbCr_Capture",
+		 {"HD_1080p_ST425_Dual_3Ga_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  2,
+		  0,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch2}][0]->fb[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_Dual_3Ga}},
+		{"HD_1080p_ST425_Dual_3Gb_YCbCr_Capture",
+		 {"HD_1080p_ST425_Dual_3Gb_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  2,
+		  0,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch2}][0]->fb[{ch2}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_Dual_3Gb}},
+		{"UHD4K_ST292_Quad_1_5_Squares_YCbCr_Capture",
+		 {"UHD4K_ST292_Quad_1_5_Squares_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  kEnable4KSquares,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch2}][0]->fb[{ch2}][0];"
+		  "sdi[{ch3}][0]->fb[{ch3}][0];"
+		  "sdi[{ch4}][0]->fb[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080}},
+		{"UHD4K_ST425_Quad_3Ga_Squares_YCbCr_Capture",
+		 {"UHD4K_ST425_Quad_3Ga_Squares_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  kEnable4KSquares,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch2}][0]->fb[{ch2}][0];"
+		  "sdi[{ch3}][0]->fb[{ch3}][0];"
+		  "sdi[{ch4}][0]->fb[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Ga}},
+		{"UHD4K_ST425_Quad_3Gb_Squares_YCbCr_Capture",
+		 {"UHD4K_ST425_Quad_3Gb_Squares_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  kEnable4KSquares | kConvert3GIn,
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];"
+		  "sdi[{ch2}][0]->fb[{ch2}][0];"
+		  "sdi[{ch3}][0]->fb[{ch3}][0];"
+		  "sdi[{ch4}][0]->fb[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink_3Gb}},
+		{"UHD4K_ST425_Dual_3Gb_2SI_YCbCr_Capture",
+		 {"UHD4K_ST425_Dual_3Gb_2SI_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  2,
+		  kConvert3GIn | kEnable4KTSI,
+		  false,
+		  "sdi[{ch1}][0]->tsi[{ch1}][0];"
+		  "sdi[{ch1}][1]->tsi[{ch1}][1];"
+		  "sdi[{ch2}][0]->tsi[{ch2}][0];"
+		  "sdi[{ch2}][1]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->fb[{ch1}][0];"
+		  "tsi[{ch1}][1]->fb[{ch1}][1];"
+		  "tsi[{ch2}][0]->fb[{ch2}][0];"
+		  "tsi[{ch2}][1]->fb[{ch2}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_DualLink}},
+		{"UHD4K_ST425_Quad_3Ga_2SI_YCbCr_Capture",
+		 {"UHD4K_ST425_Quad_3Ga_2SI_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  kEnable4KTSI,
+		  false,
+		  "sdi[{ch1}][0]->tsi[{ch1}][0];"
+		  "sdi[{ch2}][0]->tsi[{ch1}][1];"
+		  "sdi[{ch3}][0]->tsi[{ch2}][0];"
+		  "sdi[{ch4}][0]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->fb[{ch1}][0];"
+		  "tsi[{ch1}][1]->fb[{ch1}][1];"
+		  "tsi[{ch2}][0]->fb[{ch2}][0];"
+		  "tsi[{ch2}][1]->fb[{ch2}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadLink_3Ga}},
+		{"UHD4K_ST425_Quad_3Gb_2SI_YCbCr_Capture",
+		 {"UHD4K_ST425_Quad_3Gb_2SI_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  (kConvert3GIn | kEnable4KTSI),
+		  false,
+		  "sdi[{ch1}][0]->tsi[{ch1}][0];"
+		  "sdi[{ch2}][0]->tsi[{ch1}][1];"
+		  "sdi[{ch3}][0]->tsi[{ch2}][0];"
+		  "sdi[{ch4}][0]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->fb[{ch1}][0];"
+		  "tsi[{ch1}][1]->fb[{ch1}][1];"
+		  "tsi[{ch2}][0]->fb[{ch2}][0];"
+		  "tsi[{ch2}][1]->fb[{ch2}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadDualLink_3Gb}},
+		{"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Capture",
+		 {"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  (kEnable6GOut | kEnable4KTSI),
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_6Gb}},
+		{"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Capture (Kona5/io4K+)",
+		 {"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Capture (Kona5/io4K+)",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  (kEnable6GOut | kEnable4KTSI),
+		  false,
+		  "sdi[{ch1}][0]->tsi[{ch1}][0];"
+		  "sdi[{ch2}][0]->tsi[{ch1}][1];"
+		  "sdi[{ch3}][0]->tsi[{ch2}][0];"
+		  "sdi[{ch4}][0]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->fb[{ch1}][0];"
+		  "tsi[{ch1}][1]->fb[{ch1}][1];"
+		  "tsi[{ch2}][0]->fb[{ch2}][0];"
+		  "tsi[{ch2}][1]->fb[{ch2}][1];",
+		  {DEVICE_ID_KONA5, DEVICE_ID_IO4KPLUS},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_6Gb}},
+		{"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Capture",
+		 {"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  1,
+		  1,
+		  (kEnable12GOut | kConvert3GaRGBOut | kEnable4KTSI),
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_12Gb}},
+		{"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Capture (Kona5/io4K+)",
+		 {"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Capture (Kona5/io4K+)",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  (kEnable6GOut | kEnable4KTSI),
+		  false,
+		  "sdi[{ch1}][0]->tsi[{ch1}][0];"
+		  "sdi[{ch2}][0]->tsi[{ch1}][1];"
+		  "sdi[{ch3}][0]->tsi[{ch2}][0];"
+		  "sdi[{ch4}][0]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->fb[{ch1}][0];"
+		  "tsi[{ch1}][1]->fb[{ch1}][1];"
+		  "tsi[{ch2}][0]->fb[{ch2}][0];"
+		  "tsi[{ch2}][1]->fb[{ch2}][1];",
+		  {DEVICE_ID_KONA5, DEVICE_ID_IO4KPLUS},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_12Gb}},
+		// TODO
+		{"UHD28K_ST2082_Dual_12G_YCbCr_Capture",
+		 {"UHD28K_ST2082_Dual_12G_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  2,
+		  2,
+		  (kEnable12GOut | kConvert3GaRGBOut | kEnable4KTSI),
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_4320_DualLink_12Gb}},
+		// TODO
+		{"UHD28K_ST2082_Quad_12G_YCbCr_Capture",
+		 {"UHD28K_ST2082_Quad_12G_YCbCr_Capture",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_CAPTURE,
+		  4,
+		  4,
+		  (kEnable12GOut | kConvert3GaRGBOut | kEnable4KTSI),
+		  false,
+		  "sdi[{ch1}][0]->fb[{ch1}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_4320_QuadLink_12Gb}},
+		/*
+        * SDI YCbCr Display
+        */
+		{"SD_ST352_YCbCr_Display",
+		 {"SD_ST352_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::SD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_483_576}},
+		{"HD_720p_ST292_YCbCr_Display",
+		 {"HD_720p_ST292_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720}},
+		{"HD_1080_ST292_YCbCr_Display",
+		 {"HD_1080_ST292_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  0,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080}},
+		{"HD_1080_ST372_Dual_YCbCr_Display",
+		 {"HD_1080_ST372_Dual_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  2,
+		  2,
+		  0,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch2}][0]",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink}},
+		{"HD_720p_ST425_3Ga_YCbCr_Display",
+		 {"HD_720p_ST425_3Ga_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  kEnable3GOut,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Ga}},
+		{"HD_1080p_ST425_3Ga_YCbCr_Display",
+		 {"HD_1080p_ST425_3Ga_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  kEnable3GOut,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Ga}},
+		{"HD_1080p_ST425_3Gb_DL_YCbCr_Display",
+		 {"HD_1080p_ST425_3Gb_DL_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  (kEnable3GOut | kConvert3GIn | kConvert3GOut),
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink_3Gb}},
+		{"HD_720p_ST425_3Gb_YCbCr_Display",
+		 {"HD_720p_ST425_3Gb_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  2,
+		  kEnable3GOut,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_720_3Gb}},
+		{"HD_1080p_ST425_3Gb_YCbCr_Display",
+		 {"HD_1080p_ST425_3Gb_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  2,
+		  kEnable3GOut,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Gb}},
+		{"HD_1080p_ST425_Dual_3Ga_YCbCr_Display",
+		 {"HD_1080p_ST425_Dual_3Ga_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  2,
+		  2,
+		  kEnable3GOut,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_Dual_3Ga}},
+		{"HD_1080p_ST425_Dual_3Gb_YCbCr_Display",
+		 {"HD_1080p_ST425_Dual_3Gb_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  2,
+		  2,
+		  kEnable3GOut,
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch1}][1];",
+		  {},
+		  RasterDefinition::HD,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_Dual_3Gb}},
+		{"UHD4K_ST292_Quad_1_5_Squares_YCbCr_Display",
+		 {"UHD4K_ST292_Quad_1_5_Squares_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GbOut | kEnable4KSquares),
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch2}][0];"
+		  "fb[{ch3}][0]->sdi[{ch3}][0];"
+		  "fb[{ch4}][0]->sdi[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080}},
+		{"UHD4K_ST425_Quad_3Ga_Squares_YCbCr_Display",
+		 {"UHD4K_ST425_Quad_3Ga_Squares_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable3GbOut),
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch2}][0];"
+		  "fb[{ch3}][0]->sdi[{ch3}][0];"
+		  "fb[{ch4}][0]->sdi[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_3Ga}},
+		{"UHD4K_ST425_Quad_3Gb_Squares_YCbCr_Display",
+		 {"UHD4K_ST425_Quad_3Gb_Squares_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable3GbOut | kEnable4KSquares),
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];"
+		  "fb[{ch2}][0]->sdi[{ch2}][0];"
+		  "fb[{ch3}][0]->sdi[{ch3}][0];"
+		  "fb[{ch4}][0]->sdi[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_1080_DualLink_3Gb}},
+		{"UHD4K_ST425_Dual_3Gb_2SI_YCbCr_Display",
+		 {"UHD4K_ST425_Dual_3Gb_2SI_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  2,
+		  2,
+		  (kEnable3GOut | kEnable4KTSI),
+		  false,
+		  "fb[{ch1}][0]->tsi[{ch1}][0];"
+		  "fb[{ch1}][1]->tsi[{ch1}][1];"
+		  "fb[{ch2}][0]->tsi[{ch2}][0];"
+		  "fb[{ch2}][1]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->sdi[{ch1}][0];"
+		  "tsi[{ch1}][1]->sdi[{ch1}][1];"
+		  "tsi[{ch2}][0]->sdi[{ch2}][0];"
+		  "tsi[{ch2}][1]->sdi[{ch2}][1];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_DualLink}},
+		{"UHD4K_ST425_Quad_3Ga_2SI_YCbCr_Display",
+		 {"UHD4K_ST425_Quad_3Ga_2SI_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GOut | kEnable4KTSI),
+		  false,
+		  "fb[{ch1}][0]->tsi[{ch1}][0];"
+		  "fb[{ch1}][1]->tsi[{ch1}][1];"
+		  "fb[{ch2}][0]->tsi[{ch2}][0];"
+		  "fb[{ch2}][1]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->sdi[{ch1}][0];"
+		  "tsi[{ch1}][1]->sdi[{ch2}][0];"
+		  "tsi[{ch2}][0]->sdi[{ch3}][0];"
+		  "tsi[{ch2}][1]->sdi[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadLink_3Ga}},
+		{"UHD4K_ST425_Quad_3Gb_2SI_YCbCr_Display",
+		 {"UHD4K_ST425_Quad_3Gb_2SI_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable3GOut | kConvert3GaRGBOut | kEnable4KTSI),
+		  false,
+		  "fb[{ch1}][0]->tsi[{ch1}][0];"
+		  "fb[{ch1}][1]->tsi[{ch1}][1];"
+		  "fb[{ch2}][0]->tsi[{ch2}][0];"
+		  "fb[{ch2}][1]->tsi[{ch2}][1];"
+		  "tsi[{ch1}][0]->sdi[{ch1}][0];"
+		  "tsi[{ch1}][1]->sdi[{ch2}][0];"
+		  "tsi[{ch2}][0]->sdi[{ch3}][0];"
+		  "tsi[{ch2}][1]->sdi[{ch4}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_QuadDualLink_3Gb}},
+		{"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Display",
+		 {"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  (kEnable6GOut | kEnable4KTSI),
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_6Gb}},
+		{"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Display (Kona5/io4K+)",
+		 {"UHD4K_ST2018_6G_Squares_2SI_YCbCr_Display (Kona5/io4K+)",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable6GOut | kEnable4KTSI),
+		  false,
+		  "fb[{ch3}][0]->tsi[{ch3}][0];"
+		  "fb[{ch3}][1]->tsi[{ch3}][1];"
+		  "fb[{ch4}][0]->tsi[{ch4}][0];"
+		  "fb[{ch4}][1]->tsi[{ch4}][1];"
+		  "tsi[{ch3}][0]->sdi[{ch1}][0];"
+		  "tsi[{ch3}][1]->sdi[{ch2}][0];"
+		  "tsi[{ch4}][0]->sdi[{ch3}][0];"
+		  "tsi[{ch4}][1]->sdi[{ch4}][0];",
+		  {DEVICE_ID_KONA5, DEVICE_ID_IO4KPLUS},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_6Gb}},
+		{"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Display",
+		 {"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  1,
+		  1,
+		  (kEnable12GOut | kEnable4KTSI),
+		  false,
+		  "fb[{ch1}][0]->sdi[{ch1}][0];",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_12Gb}},
+		{"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Display (Kona5/io4K+)",
+		 {"UHD4K_ST2018_12G_Squares_2SI_YCbCr_Display (Kona5/io4K+)",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable12GOut | kConvert3GOut | kEnable4KTSI),
+		  false,
+		  "fb[{ch3}][0]->tsi[{ch3}][0];"
+		  "fb[{ch3}][1]->tsi[{ch3}][1];"
+		  "fb[{ch4}][0]->tsi[{ch4}][0];"
+		  "fb[{ch4}][1]->tsi[{ch4}][1];"
+		  "tsi[{ch3}][0]->sdi[{ch1}][0];"
+		  "tsi[{ch3}][1]->sdi[{ch2}][0];"
+		  "tsi[{ch4}][0]->sdi[{ch3}][0];"
+		  "tsi[{ch4}][1]->sdi[{ch4}][0];",
+		  {DEVICE_ID_KONA5, DEVICE_ID_IO4KPLUS},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_2160_Single_12Gb}},
+		// TODO
+		{"UHD28K_ST2082_Dual_12G_YCbCr_Display",
+		 {"UHD28K_ST2082_Dual_12G_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  2,
+		  2,
+		  (kEnable12GOut | kConvert3GOut | kEnable4KTSI),
+		  false,
+		  "",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_4320_DualLink_12Gb}},
+		// TODO
+		{"UHD28K_ST2082_Quad_12G_YCbCr_Display",
+		 {"UHD28K_ST2082_Quad_12G_YCbCr_Display",
+		  ConnectionKind::SDI,
+		  NTV2_MODE_DISPLAY,
+		  4,
+		  4,
+		  (kEnable12GOut | kConvert3GOut | kEnable4KTSI),
+		  false,
+		  "",
+		  {},
+		  RasterDefinition::UHD_4K,
+		  HDMIWireFormat::Unknown,
+		  VPIDStandard_4320_QuadLink_12Gb}},
+	};
+	for (auto &&rp : kRoutingPresets)
+		AddPreset(std::move(rp.first), std::move(rp.second));
+}
+
+RoutingPresetMap RoutingConfigurator::GetPresetTable() const
+{
+	return m_presets;
+}
+
+bool RoutingConfigurator::FindFirstPreset(ConnectionKind kind, NTV2DeviceID id,
+					  NTV2Mode mode, NTV2VideoFormat vf,
+					  NTV2PixelFormat pf,
+					  VPIDStandard standard,
+					  RoutingPreset &preset)
+{
+	// if (NTV2DeviceCanDoVideoFormat(id, vf) &&
+	//     NTV2DeviceCanDoFrameBufferFormat(id, pf)) {
+	{
+		const auto &rd = DetermineRasterDefinition(vf);
+		bool is_rgb = NTV2_IS_FBF_RGB(pf);
+		std::vector<RoutingPresetPair> query;
+		for (const auto &p : m_presets) {
+			if (p.second.kind == kind && p.second.mode == mode &&
+			    p.second.raster_def == rd &&
+			    p.second.is_rgb == is_rgb &&
+			    p.second.vpid_standard == standard) {
+				query.push_back(p);
+			}
+		}
+		RoutingPresets device_presets;
+		for (const auto &q : query) {
+			for (const auto &device_id : q.second.device_ids) {
+				if (device_id == id)
+					device_presets.push_back(q.second);
+			}
+		}
+		if (device_presets.size() > 0) {
+			preset = device_presets.at(0);
+			return true;
+		}
+		if (query.size() > 0) {
+			preset = query.at(0).second;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+} // aja

+ 48 - 0
plugins/aja/aja-presets.hpp

@@ -0,0 +1,48 @@
+#pragma once
+
+#include "aja-enums.hpp"
+
+#include <ajantv2/includes/ntv2enums.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace aja {
+
+struct RoutingPreset {
+	std::string name;
+	ConnectionKind kind;
+	NTV2Mode mode;
+	uint32_t num_channels;
+	uint32_t num_framestores;
+	uint32_t flags;
+	bool is_rgb;
+	std::string route_string;
+	std::vector<NTV2DeviceID> device_ids;
+	RasterDefinition raster_def;
+	HDMIWireFormat hdmi_wire_format;
+	VPIDStandard vpid_standard;
+};
+
+using RoutingPresets = std::vector<RoutingPreset>;
+using RoutingPresetPair = std::pair<std::string, RoutingPreset>;
+using RoutingPresetMap = std::map<std::string, RoutingPreset>;
+
+class RoutingConfigurator {
+public:
+	RoutingConfigurator();
+	void AddPreset(const std::string &name, const RoutingPreset &preset);
+	bool PresetByName(const std::string &name, RoutingPreset &preset) const;
+	RoutingPresetMap GetPresetTable() const;
+	bool FindFirstPreset(ConnectionKind kind, NTV2DeviceID id,
+			     NTV2Mode mode, NTV2VideoFormat vf,
+			     NTV2PixelFormat pf, VPIDStandard standard,
+			     RoutingPreset &preset);
+
+private:
+	void build_preset_table();
+	RoutingPresetMap m_presets;
+};
+
+} // aja

+ 40 - 123
plugins/aja/aja-props.cpp

@@ -1,129 +1,18 @@
 #include "aja-props.hpp"
+#include "aja-common.hpp"
 
 #include <ajantv2/includes/ntv2devicefeatures.h>
 #include <ajantv2/includes/ntv2utils.h>
-#include <ajantv2/includes/ntv2vpid.h>
-
-VPIDData::VPIDData()
-	: mVpidA{0},
-	  mVpidB{0},
-	  mStandardA{VPIDStandard_Unknown},
-	  mStandardB{VPIDStandard_Unknown},
-	  mSamplingA{VPIDSampling_XYZ_444},
-	  mSamplingB{VPIDSampling_XYZ_444}
-{
-}
-
-VPIDData::VPIDData(ULWord vpidA, ULWord vpidB)
-	: mVpidA{vpidA},
-	  mVpidB{vpidB},
-	  mStandardA{VPIDStandard_Unknown},
-	  mStandardB{VPIDStandard_Unknown},
-	  mSamplingA{VPIDSampling_XYZ_444},
-	  mSamplingB{VPIDSampling_XYZ_444}
-{
-	Parse();
-}
-
-VPIDData::VPIDData(const VPIDData &other)
-	: mVpidA{other.mVpidA},
-	  mVpidB{other.mVpidB},
-	  mStandardA{VPIDStandard_Unknown},
-	  mStandardB{VPIDStandard_Unknown},
-	  mSamplingA{VPIDSampling_XYZ_444},
-	  mSamplingB{VPIDSampling_XYZ_444}
-{
-	Parse();
-}
-VPIDData::VPIDData(VPIDData &&other)
-	: mVpidA{other.mVpidA},
-	  mVpidB{other.mVpidB},
-	  mStandardA{VPIDStandard_Unknown},
-	  mStandardB{VPIDStandard_Unknown},
-	  mSamplingA{VPIDSampling_XYZ_444},
-	  mSamplingB{VPIDSampling_XYZ_444}
-{
-	Parse();
-}
-
-VPIDData &VPIDData::operator=(const VPIDData &other)
-{
-	mVpidA = other.mVpidA;
-	mVpidB = other.mVpidB;
-	return *this;
-}
-
-VPIDData &VPIDData::operator=(VPIDData &&other)
-{
-	mVpidA = other.mVpidA;
-	mVpidB = other.mVpidB;
-	return *this;
-}
-
-bool VPIDData::operator==(const VPIDData &rhs) const
-{
-	return (mVpidA == rhs.mVpidA && mVpidB == rhs.mVpidB);
-}
-
-bool VPIDData::operator!=(const VPIDData &rhs) const
-{
-	return !operator==(rhs);
-}
-
-void VPIDData::SetA(ULWord vpidA)
-{
-	mVpidA = vpidA;
-}
-
-void VPIDData::SetB(ULWord vpidB)
-{
-	mVpidB = vpidB;
-}
-
-void VPIDData::Parse()
-{
-	CNTV2VPID parserA;
-	parserA.SetVPID(mVpidA);
-	mStandardA = parserA.GetStandard();
-	mSamplingA = parserA.GetSampling();
-
-	CNTV2VPID parserB;
-	parserB.SetVPID(mVpidB);
-	mStandardB = parserB.GetStandard();
-	mSamplingB = parserB.GetSampling();
-}
-
-bool VPIDData::IsRGB() const
-{
-	switch (mSamplingA) {
-	default:
-		break;
-	case VPIDSampling_GBR_444:
-	case VPIDSampling_GBRA_4444:
-	case VPIDSampling_GBRD_4444:
-		return true;
-	}
-	return false;
-}
-
-VPIDStandard VPIDData::Standard() const
-{
-	return mStandardA;
-}
-
-VPIDSampling VPIDData::Sampling() const
-{
-	return mSamplingA;
-}
 
 // AJASource Properties
 SourceProps::SourceProps()
 	: deviceID{DEVICE_ID_NOTFOUND},
 	  ioSelect{IOSelection::Invalid},
-	  inputSource{NTV2_INPUTSOURCE_INVALID},
+	  //   inputSource{NTV2_INPUTSOURCE_INVALID},
 	  videoFormat{NTV2_FORMAT_UNKNOWN},
 	  pixelFormat{NTV2_FBF_INVALID},
-	  sdi4kTransport{SDI4KTransport::TwoSampleInterleave},
+	  sdiTransport{SDITransport::SingleLink},
+	  sdi4kTransport{SDITransport4K::TwoSampleInterleave},
 	  audioNumChannels{8},
 	  audioSampleSize{4},
 	  audioSampleRate{48000},
@@ -136,10 +25,11 @@ SourceProps::SourceProps()
 SourceProps::SourceProps(NTV2DeviceID devID)
 	: deviceID{devID},
 	  ioSelect{IOSelection::Invalid},
-	  inputSource{NTV2_INPUTSOURCE_INVALID},
+	  //   inputSource{NTV2_INPUTSOURCE_INVALID},
 	  videoFormat{NTV2_FORMAT_UNKNOWN},
 	  pixelFormat{NTV2_FBF_INVALID},
-	  sdi4kTransport{SDI4KTransport::TwoSampleInterleave},
+	  sdiTransport{SDITransport::SingleLink},
+	  sdi4kTransport{SDITransport4K::TwoSampleInterleave},
 	  audioNumChannels{8},
 	  audioSampleSize{4},
 	  audioSampleRate{48000},
@@ -153,9 +43,10 @@ SourceProps::SourceProps(const SourceProps &props)
 {
 	deviceID = props.deviceID;
 	ioSelect = props.ioSelect;
-	inputSource = props.inputSource;
+	// inputSource = props.inputSource;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -169,9 +60,10 @@ SourceProps::SourceProps(SourceProps &&props)
 {
 	deviceID = props.deviceID;
 	ioSelect = props.ioSelect;
-	inputSource = props.inputSource;
+	// inputSource = props.inputSource;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -185,9 +77,10 @@ void SourceProps::operator=(const SourceProps &props)
 {
 	deviceID = props.deviceID;
 	ioSelect = props.ioSelect;
-	inputSource = props.inputSource;
+	// inputSource = props.inputSource;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -201,9 +94,10 @@ void SourceProps::operator=(SourceProps &&props)
 {
 	deviceID = props.deviceID;
 	ioSelect = props.ioSelect;
-	inputSource = props.inputSource;
+	// inputSource = props.inputSource;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -221,6 +115,7 @@ bool SourceProps::operator==(const SourceProps &props)
 		pixelFormat == props.pixelFormat &&
 		// vpid == props.vpid &&
 		autoDetect == props.autoDetect &&
+		sdiTransport == props.sdiTransport &&
 		sdi4kTransport == props.sdi4kTransport &&
 		audioNumChannels == props.audioNumChannels &&
 		audioSampleSize == props.audioSampleSize &&
@@ -233,9 +128,25 @@ bool SourceProps::operator!=(const SourceProps &props)
 	return !operator==(props);
 }
 
+NTV2InputSource SourceProps::InitialInputSource() const
+{
+	auto inputSources = InputSources();
+	if (!inputSources.empty()) {
+		return *inputSources.begin();
+	}
+	return NTV2_INPUTSOURCE_INVALID;
+}
+
+NTV2InputSourceSet SourceProps::InputSources() const
+{
+	NTV2InputSourceSet inputSources;
+	aja::IOSelectionToInputSources(ioSelect, inputSources);
+	return inputSources;
+}
+
 NTV2Channel SourceProps::Channel() const
 {
-	return NTV2InputSourceToChannel(inputSource);
+	return NTV2InputSourceToChannel(InitialInputSource());
 }
 
 NTV2AudioSystem SourceProps::AudioSystem() const
@@ -291,7 +202,7 @@ OutputProps::OutputProps(NTV2DeviceID devID)
 	  outputDest{NTV2_OUTPUTDESTINATION_ANALOG},
 	  videoFormat{NTV2_FORMAT_UNKNOWN},
 	  pixelFormat{NTV2_FBF_INVALID},
-	  sdi4kTransport{SDI4KTransport::TwoSampleInterleave},
+	  sdi4kTransport{SDITransport4K::TwoSampleInterleave},
 	  audioNumChannels{8},
 	  audioSampleSize{4},
 	  audioSampleRate{48000}
@@ -305,6 +216,7 @@ OutputProps::OutputProps(OutputProps &&props)
 	outputDest = props.outputDest;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -318,6 +230,7 @@ OutputProps::OutputProps(const OutputProps &props)
 	outputDest = props.outputDest;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -331,6 +244,7 @@ void OutputProps::operator=(const OutputProps &props)
 	outputDest = props.outputDest;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -344,6 +258,7 @@ void OutputProps::operator=(OutputProps &&props)
 	outputDest = props.outputDest;
 	videoFormat = props.videoFormat;
 	pixelFormat = props.pixelFormat;
+	sdiTransport = props.sdiTransport;
 	sdi4kTransport = props.sdi4kTransport;
 	audioNumChannels = props.audioNumChannels;
 	audioSampleSize = props.audioSampleSize;
@@ -356,6 +271,8 @@ bool OutputProps::operator==(const OutputProps &props)
 		// outputDest == props.outputDest &&
 		videoFormat == props.videoFormat &&
 		pixelFormat == props.pixelFormat &&
+		sdiTransport == props.sdiTransport &&
+		sdi4kTransport == props.sdi4kTransport &&
 		audioNumChannels == props.audioNumChannels &&
 		audioSampleSize == props.audioSampleSize &&
 		audioSampleRate == props.audioSampleRate);

+ 7 - 35
plugins/aja/aja-props.hpp

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "aja-enums.hpp"
+#include "aja-vpid-data.hpp"
 
 #include <media-io/audio-io.h>
 
@@ -11,38 +12,6 @@
 #include <string>
 #include <vector>
 
-class VPIDData {
-public:
-	VPIDData();
-	VPIDData(ULWord vpidA, ULWord vpidB);
-	VPIDData(const VPIDData &other);
-	VPIDData(VPIDData &&other);
-	~VPIDData() = default;
-
-	VPIDData &operator=(const VPIDData &other);
-	VPIDData &operator=(VPIDData &&other);
-	bool operator==(const VPIDData &rhs) const;
-	bool operator!=(const VPIDData &rhs) const;
-
-	void SetA(ULWord vpidA);
-	void SetB(ULWord vpidB);
-	void Parse();
-	bool IsRGB() const;
-
-	VPIDStandard Standard() const;
-	VPIDSampling Sampling() const;
-
-private:
-	ULWord mVpidA;
-	ULWord mVpidB;
-	VPIDStandard mStandardA;
-	VPIDSampling mSamplingA;
-	VPIDStandard mStandardB;
-	VPIDSampling mSamplingB;
-};
-
-using VPIDDataList = std::vector<VPIDData>;
-
 //TODO(paulh): Consolidate the two Props classes
 class SourceProps {
 public:
@@ -56,6 +25,8 @@ public:
 	bool operator==(const SourceProps &props);
 	bool operator!=(const SourceProps &props);
 
+	NTV2InputSource InitialInputSource() const;
+	NTV2InputSourceSet InputSources() const;
 	NTV2Channel Channel() const;
 	NTV2AudioSystem AudioSystem() const;
 	NTV2AudioRate AudioRate() const;
@@ -65,10 +36,10 @@ public:
 
 	NTV2DeviceID deviceID;
 	IOSelection ioSelect;
-	NTV2InputSource inputSource;
 	NTV2VideoFormat videoFormat;
 	NTV2PixelFormat pixelFormat;
-	SDI4KTransport sdi4kTransport;
+	SDITransport sdiTransport;
+	SDITransport4K sdi4kTransport;
 	VPIDDataList vpids;
 	uint32_t audioNumChannels;
 	uint32_t audioSampleSize;
@@ -101,7 +72,8 @@ public:
 	NTV2OutputDestination outputDest;
 	NTV2VideoFormat videoFormat;
 	NTV2PixelFormat pixelFormat;
-	SDI4KTransport sdi4kTransport;
+	SDITransport sdiTransport;
+	SDITransport4K sdi4kTransport;
 	uint32_t audioNumChannels;
 	uint32_t audioSampleSize;
 	uint32_t audioSampleRate;

+ 148 - 364
plugins/aja/aja-routing.cpp

@@ -3,67 +3,13 @@
 #include "aja-routing.hpp"
 #include "aja-widget-io.hpp"
 
-// Signal routing crosspoint and register setting tables for SDI/HDMI/etc.
-#include "routing/hdmi_rgb_capture.h"
-#include "routing/hdmi_rgb_display.h"
-#include "routing/hdmi_ycbcr_capture.h"
-#include "routing/hdmi_ycbcr_display.h"
-#include "routing/sdi_ycbcr_capture.h"
-#include "routing/sdi_ycbcr_display.h"
-#include "routing/sdi_rgb_capture.h"
-#include "routing/sdi_rgb_display.h"
-
 #include <ajabase/common/common.h>
 #include <ajantv2/includes/ntv2card.h>
 #include <ajantv2/includes/ntv2devicefeatures.h>
 
 #include <obs-module.h>
 
-RasterDefinition GetRasterDefinition(IOSelection io, NTV2VideoFormat vf,
-				     NTV2DeviceID deviceID)
-{
-	RasterDefinition def = RasterDefinition::Unknown;
-
-	if (NTV2_IS_SD_VIDEO_FORMAT(vf)) {
-		def = RasterDefinition::SD;
-	} else if (NTV2_IS_HD_VIDEO_FORMAT(vf)) {
-		def = RasterDefinition::HD;
-	} else if (NTV2_IS_QUAD_FRAME_FORMAT(vf)) {
-		def = RasterDefinition::UHD_4K;
-
-		/* NOTE(paulh): Special enum for Kona5 Retail & IO4K+ firmwares which route UHD/4K formats
-		 * over 1x 6G/12G SDI using an undocumented crosspoint config.
-		 */
-		if (aja::IsSDIOneWireIOSelection(io) &&
-		    aja::IsRetailSDI12G(deviceID))
-			def = RasterDefinition::UHD_4K_Retail_12G;
-	} else if (NTV2_IS_QUAD_QUAD_FORMAT(vf)) {
-		def = RasterDefinition::UHD2_8K;
-	} else {
-		def = RasterDefinition::Unknown;
-	}
-
-	return def;
-}
-
-#define NTV2UTILS_ENUM_CASE_RETURN_STR(enum_name) \
-	case (enum_name):                         \
-		return #enum_name
-std::string RasterDefinitionToString(RasterDefinition rd)
-{
-	std::string str = "";
-
-	switch (rd) {
-		NTV2UTILS_ENUM_CASE_RETURN_STR(RasterDefinition::SD);
-		NTV2UTILS_ENUM_CASE_RETURN_STR(RasterDefinition::HD);
-		NTV2UTILS_ENUM_CASE_RETURN_STR(RasterDefinition::UHD_4K);
-		NTV2UTILS_ENUM_CASE_RETURN_STR(RasterDefinition::UHD2_8K);
-		NTV2UTILS_ENUM_CASE_RETURN_STR(RasterDefinition::Unknown);
-	}
-
-	return str;
-}
-
+namespace aja {
 /*
  * Parse the widget routing shorthand string into a map of input and output NTV2CrosspointIDs.
  * For example "sdi[0][0]->fb[0][0]" is shorthand for connecting the output crosspoint for
@@ -191,137 +137,12 @@ bool Routing::ParseRouteString(const std::string &route,
 	return parse_ok > 0;
 }
 
-// Determine the appropriate SDIWireFormat based on the specified device ID and VPID specification.
-bool Routing::DetermineSDIWireFormat(NTV2DeviceID deviceID, VPIDSpec spec,
-				     SDIWireFormat &swf)
-{
-	if (deviceID == DEVICE_ID_KONA5 || deviceID == DEVICE_ID_IO4KPLUS) {
-		static const std::vector<VPIDStandard> kRetail6GVpidStandards = {
-			VPIDStandard_2160_Single_6Gb,
-			VPIDStandard_1080_Single_6Gb,
-			VPIDStandard_1080_AFR_Single_6Gb,
-		};
-		static const std::vector<VPIDStandard> kRetail12GVpidStandards =
-			{VPIDStandard_2160_Single_12Gb,
-			 VPIDStandard_1080_10_12_AFR_Single_12Gb};
-		if (spec.first == RasterDefinition::UHD_4K &&
-		    aja::vec_contains<VPIDStandard>(kRetail6GVpidStandards,
-						    spec.second)) {
-			swf = SDIWireFormat::
-				UHD4K_ST2018_6G_Squares_2SI_Kona5_io4KPlus;
-			return true;
-		} else if (spec.first == RasterDefinition::UHD_4K &&
-			   aja::vec_contains<VPIDStandard>(
-				   kRetail12GVpidStandards, spec.second)) {
-			swf = SDIWireFormat::
-				UHD4K_ST2018_12G_Squares_2SI_Kona5_io4KPlus;
-			return true;
-		} else {
-			if (kSDIWireFormats.find(spec) !=
-			    kSDIWireFormats.end()) {
-				swf = kSDIWireFormats.at(spec);
-				return true;
-			}
-		}
-	} else {
-		if (kSDIWireFormats.find(spec) != kSDIWireFormats.end()) {
-			swf = kSDIWireFormats.at(spec);
-			return true;
-		}
-	}
-
-	return false;
-}
-
-// Lookup configuration for HDMI input/output in the routing table.
-bool Routing::FindRoutingConfigHDMI(HDMIWireFormat hwf, NTV2Mode mode,
-				    bool isRGB, NTV2DeviceID deviceID,
-				    RoutingConfig &routing)
-{
-	if (isRGB) {
-		if (mode == NTV2_MODE_CAPTURE) {
-			if (kHDMIRGBCaptureConfigs.find(hwf) !=
-			    kHDMIRGBCaptureConfigs.end()) {
-				routing = kHDMIRGBCaptureConfigs.at(hwf);
-				return true;
-			}
-		} else {
-			if (deviceID == DEVICE_ID_TTAP_PRO) {
-				routing = kHDMIRGBDisplayConfigs.at(
-					HDMIWireFormat::TTAP_PRO);
-				return true;
-			}
-			if (kHDMIRGBDisplayConfigs.find(hwf) !=
-			    kHDMIRGBDisplayConfigs.end()) {
-				routing = kHDMIRGBDisplayConfigs.at(hwf);
-				return true;
-			}
-		}
-	} else {
-		if (mode == NTV2_MODE_CAPTURE) {
-			if (kHDMIYCbCrCaptureConfigs.find(hwf) !=
-			    kHDMIYCbCrCaptureConfigs.end()) {
-				routing = kHDMIYCbCrCaptureConfigs.at(hwf);
-				return true;
-			}
-		} else {
-			if (kHDMIYCbCrDisplayConfigs.find(hwf) !=
-			    kHDMIYCbCrDisplayConfigs.end()) {
-				routing = kHDMIYCbCrDisplayConfigs.at(hwf);
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
-// Lookup configuration for SDI input/output in the routing table.
-bool Routing::FindRoutingConfigSDI(SDIWireFormat swf, NTV2Mode mode, bool isRGB,
-				   NTV2DeviceID deviceID,
-				   RoutingConfig &routing)
-{
-	UNUSED_PARAMETER(deviceID);
-
-	if (isRGB) {
-		if (mode == NTV2_MODE_CAPTURE) {
-			if (kSDIRGBCaptureConfigs.find(swf) !=
-			    kSDIRGBCaptureConfigs.end()) {
-				routing = kSDIRGBCaptureConfigs.at(swf);
-				return true;
-			}
-		} else if (mode == NTV2_MODE_DISPLAY) {
-			if (kSDIRGBDisplayConfigs.find(swf) !=
-			    kSDIRGBDisplayConfigs.end()) {
-				routing = kSDIRGBDisplayConfigs.at(swf);
-				return true;
-			}
-		}
-	} else {
-		if (mode == NTV2_MODE_CAPTURE) {
-			if (kSDIYCbCrCaptureConfigs.find(swf) !=
-			    kSDIYCbCrCaptureConfigs.end()) {
-				routing = kSDIYCbCrCaptureConfigs.at(swf);
-				return true;
-			}
-		} else if (mode == NTV2_MODE_DISPLAY) {
-			if (kSDIYCbCrDisplayConfigs.find(swf) !=
-			    kSDIYCbCrDisplayConfigs.end()) {
-				routing = kSDIYCbCrDisplayConfigs.at(swf);
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
 void Routing::StartSourceAudio(const SourceProps &props, CNTV2Card *card)
 {
 	if (!card)
 		return;
 
-	auto inputSrc = props.inputSource;
+	auto inputSrc = props.InitialInputSource();
 	auto channel = props.Channel();
 	auto audioSys = props.AudioSystem();
 
@@ -383,118 +204,42 @@ void Routing::StopSourceAudio(const SourceProps &props, CNTV2Card *card)
 	}
 }
 
-// Guess an SDIWireFormat based on specified Video Format, IOSelection, 4K Transport and device ID.
-SDIWireFormat GuessSDIWireFormat(NTV2VideoFormat vf, IOSelection io,
-				 SDI4KTransport t4k,
-				 NTV2DeviceID device_id = DEVICE_ID_NOTFOUND)
-{
-	auto rd = GetRasterDefinition(io, vf, device_id);
-	auto fg = GetNTV2FrameGeometryFromVideoFormat(vf);
-
-	SDIWireFormat swf = SDIWireFormat::Unknown;
-	if (rd == RasterDefinition::SD) {
-		swf = SDIWireFormat::SD_ST352;
-	} else if (rd == RasterDefinition::HD) {
-		if (fg == NTV2_FG_1280x720) {
-			swf = SDIWireFormat::HD_720p_ST292;
-		} else if (fg == NTV2_FG_1920x1080 || fg == NTV2_FG_2048x1080) {
-			swf = SDIWireFormat::HD_1080_ST292;
-		}
-	} else if (rd == RasterDefinition::UHD_4K) {
-		if (t4k == SDI4KTransport::Squares) {
-			if (aja::IsSDIFourWireIOSelection(io)) {
-				swf = SDIWireFormat::UHD4K_ST292_Quad_1_5_Squares;
-			} else if (aja::IsSDITwoWireIOSelection(io)) {
-				swf = SDIWireFormat::UHD4K_ST292_Dual_1_5_Squares;
-			}
-		} else if (t4k == SDI4KTransport::TwoSampleInterleave) {
-			if (aja::IsSDIOneWireIOSelection(io)) {
-				if (NTV2_IS_4K_HFR_VIDEO_FORMAT(vf)) {
-					if (aja::IsRetailSDI12G(device_id)) {
-						swf = SDIWireFormat::
-							UHD4K_ST2018_12G_Squares_2SI_Kona5_io4KPlus;
-					} else {
-						swf = SDIWireFormat::
-							UHD4K_ST2018_12G_Squares_2SI;
-					}
-				} else {
-					if (aja::IsRetailSDI12G(device_id)) {
-						swf = SDIWireFormat::
-							UHD4K_ST2018_6G_Squares_2SI_Kona5_io4KPlus;
-					} else {
-						swf = SDIWireFormat::
-							UHD4K_ST2018_6G_Squares_2SI;
-					}
-				}
-			} else if (aja::IsSDITwoWireIOSelection(io)) {
-				swf = SDIWireFormat::UHD4K_ST425_Dual_3Gb_2SI;
-			} else if (aja::IsSDIFourWireIOSelection(io)) {
-				swf = SDIWireFormat::UHD4K_ST425_Quad_3Gb_2SI;
-			}
-		}
-	}
-	return swf;
-}
-
 bool Routing::ConfigureSourceRoute(const SourceProps &props, NTV2Mode mode,
 				   CNTV2Card *card)
 {
 	if (!card)
 		return false;
 
+	bool found_preset = false;
 	auto deviceID = props.deviceID;
-
 	NTV2VideoFormat vf = props.videoFormat;
-	if (NTV2_VIDEO_FORMAT_IS_B(props.videoFormat)) {
-		vf = aja::GetLevelAFormatForLevelBFormat(props.videoFormat);
-	}
 
-	NTV2InputSourceSet inputSources;
-	aja::IOSelectionToInputSources(props.ioSelect, inputSources);
-	if (inputSources.empty()) {
-		blog(LOG_DEBUG,
-		     "No Input Sources specified to configure routing!");
-		return false;
-	}
-	auto init_src = *inputSources.begin();
-	auto init_channel = NTV2InputSourceToChannel(init_src);
-
-	RoutingConfig rc;
+	auto init_src = props.InitialInputSource();
+	auto init_channel = props.Channel();
+	RoutingConfigurator rc;
+	RoutingPreset rp;
 	if (NTV2_INPUT_SOURCE_IS_SDI(init_src)) {
-		SDIWireFormat swf = SDIWireFormat::Unknown;
-		auto standard = VPIDStandard_Unknown;
-		auto vpidList = props.vpids;
-		if (vpidList.size() > 0)
-			standard = vpidList.at(0).Standard();
-
-		if (standard != VPIDStandard_Unknown) {
-			// Determine SDI format based on raster "definition" and VPID byte 1 value (AKA SMPTE standard)
-			auto rasterDef = GetRasterDefinition(props.ioSelect, vf,
-							     props.deviceID);
-			VPIDSpec vpidSpec = std::make_pair(rasterDef, standard);
-			DetermineSDIWireFormat(deviceID, vpidSpec, swf);
-		} else {
-			// Best guess SDI format from incoming video format if no VPIDs detected
-			swf = GuessSDIWireFormat(vf, props.ioSelect,
-						 props.sdi4kTransport,
-						 props.deviceID);
+		auto vpidStandard = VPIDStandard_Unknown;
+		if (props.autoDetect) {
+			auto vpidList = props.vpids;
+			if (vpidList.size() > 0)
+				vpidStandard = vpidList.at(0).Standard();
 		}
-
-		if (swf == SDIWireFormat::Unknown) {
-			blog(LOG_DEBUG, "Could not determine SDI Wire Format!");
-			return false;
+		if (vpidStandard == VPIDStandard_Unknown) {
+			vpidStandard = DetermineVPIDStandard(
+				deviceID, props.ioSelect, props.videoFormat,
+				props.pixelFormat, props.sdiTransport,
+				props.sdi4kTransport);
 		}
-
-		if (!FindRoutingConfigSDI(swf, mode,
-					  NTV2_IS_FBF_RGB(props.pixelFormat),
-					  props.deviceID, rc)) {
-			blog(LOG_DEBUG,
-			     "Could not find RoutingConfig for SDI Wire Format!");
+		if (!rc.FindFirstPreset(ConnectionKind::SDI, props.deviceID,
+					NTV2_MODE_CAPTURE, vf,
+					props.pixelFormat, vpidStandard, rp)) {
+			blog(LOG_WARNING,
+			     "No SDI capture routing preset found!");
 			return false;
 		}
 	} else if (NTV2_INPUT_SOURCE_IS_HDMI(init_src)) {
 		HDMIWireFormat hwf = HDMIWireFormat::Unknown;
-
 		if (NTV2_IS_FBF_RGB(props.pixelFormat)) {
 			if (NTV2_IS_HD_VIDEO_FORMAT(vf))
 				hwf = HDMIWireFormat::HD_RGB_LFR;
@@ -504,18 +249,20 @@ bool Routing::ConfigureSourceRoute(const SourceProps &props, NTV2Mode mode,
 			else if (NTV2_IS_4K_VIDEO_FORMAT(vf))
 				hwf = HDMIWireFormat::UHD_4K_YCBCR_LFR;
 		}
-
-		if (!FindRoutingConfigHDMI(hwf, mode,
-					   NTV2_IS_FBF_RGB(props.pixelFormat),
-					   props.deviceID, rc)) {
-			blog(LOG_DEBUG,
-			     "Could not find RoutingConfig for HDMI Wire Format!");
+		if (!rc.FindFirstPreset(ConnectionKind::HDMI, props.deviceID,
+					NTV2_MODE_CAPTURE, vf,
+					props.pixelFormat, VPIDStandard_Unknown,
+					rp)) {
+			blog(LOG_WARNING,
+			     "No HDMI capture routing preset found!");
 			return false;
 		}
 	}
 
+	LogRoutingPreset(rp);
+
 	// Substitute channel placeholders for actual indices
-	std::string route_string = rc.route_string;
+	std::string route_string = rp.route_string;
 	ULWord start_channel_index = GetIndexForNTV2Channel(init_channel);
 	for (ULWord c = 0; c < 8; c++) {
 		std::string channel_placeholder =
@@ -526,43 +273,45 @@ bool Routing::ConfigureSourceRoute(const SourceProps &props, NTV2Mode mode,
 	}
 
 	NTV2XptConnections cnx;
-	ParseRouteString(route_string, cnx);
+	if (!ParseRouteString(route_string, cnx))
+		return false;
 
 	card->ApplySignalRoute(cnx, false);
 
 	// Apply SDI widget settings
 	start_channel_index = GetIndexForNTV2Channel(init_channel);
 	for (uint32_t i = (uint32_t)start_channel_index;
-	     i < (start_channel_index + rc.num_wires); i++) {
+	     i < (start_channel_index + rp.num_channels); i++) {
 		NTV2Channel channel = GetNTV2ChannelForIndex(i);
 		if (::NTV2DeviceHasBiDirectionalSDI(deviceID)) {
 			card->SetSDITransmitEnable(channel,
 						   mode == NTV2_MODE_DISPLAY);
 		}
-		card->SetSDIOut3GEnable(channel, rc.enable_3g_out);
-		card->SetSDIOut3GbEnable(channel, rc.enable_3gb_out);
-		card->SetSDIOut6GEnable(channel, rc.enable_6g_out);
-		card->SetSDIOut12GEnable(channel, rc.enable_12g_out);
+		card->SetSDIOut3GEnable(channel, rp.flags & kEnable3GOut);
+		card->SetSDIOut3GbEnable(channel, rp.flags & kEnable3GbOut);
+		card->SetSDIOut6GEnable(channel, rp.flags & kEnable6GOut);
+		card->SetSDIOut12GEnable(channel, rp.flags & kEnable12GOut);
 		card->SetSDIInLevelBtoLevelAConversion((UWord)i,
-						       rc.convert_3g_in);
-		card->SetSDIOutLevelAtoLevelBConversion((UWord)i,
-							rc.convert_3g_out);
-		card->SetSDIOutRGBLevelAConversion((UWord)i,
-						   rc.enable_rgb_3ga_convert);
+						       rp.flags & kConvert3GIn);
+		card->SetSDIOutLevelAtoLevelBConversion(
+			(UWord)i, rp.flags & kConvert3GOut);
+		card->SetSDIOutRGBLevelAConversion(
+			(UWord)i, rp.flags & kConvert3GaRGBOut);
 	}
 
 	// Apply Framestore settings
 	for (uint32_t i = (uint32_t)start_channel_index;
-	     i < (start_channel_index + rc.num_framestores); i++) {
+	     i < (start_channel_index + rp.num_framestores); i++) {
 		NTV2Channel channel = GetNTV2ChannelForIndex(i);
 		card->EnableChannel(channel);
 		card->SetMode(channel, mode);
 		card->SetVANCMode(NTV2_VANCMODE_OFF, channel);
 		card->SetVideoFormat(vf, false, false, channel);
 		card->SetFrameBufferFormat(channel, props.pixelFormat);
-		card->SetTsiFrameEnable(rc.enable_tsi, channel);
-		card->Set4kSquaresEnable(rc.enable_4k_squares, channel);
-		card->SetQuadQuadSquaresEnable(rc.enable_8k_squares, channel);
+		card->SetTsiFrameEnable(rp.flags & kEnable4KTSI, channel);
+		card->Set4kSquaresEnable(rp.flags & kEnable4KSquares, channel);
+		card->SetQuadQuadSquaresEnable(rp.flags & kEnable8KSquares,
+					       channel);
 	}
 
 	return true;
@@ -574,8 +323,8 @@ bool Routing::ConfigureOutputRoute(const OutputProps &props, NTV2Mode mode,
 	if (!card)
 		return false;
 
+	bool found_preset = false;
 	auto deviceID = props.deviceID;
-
 	NTV2OutputDestinations outputDests;
 	aja::IOSelectionToOutputDests(props.ioSelect, outputDests);
 	if (outputDests.empty()) {
@@ -586,29 +335,22 @@ bool Routing::ConfigureOutputRoute(const OutputProps &props, NTV2Mode mode,
 
 	auto init_dest = *outputDests.begin();
 	auto init_channel = NTV2OutputDestinationToChannel(init_dest);
-
-	RoutingConfig rc;
+	RoutingConfigurator rc;
+	RoutingPreset rp;
 	if (NTV2_OUTPUT_DEST_IS_SDI(init_dest)) {
-		SDIWireFormat swf = GuessSDIWireFormat(props.videoFormat,
-						       props.ioSelect,
-						       props.sdi4kTransport,
-						       props.deviceID);
-
-		if (swf == SDIWireFormat::Unknown) {
-			blog(LOG_DEBUG, "Could not determine SDI Wire Format!");
-			return false;
-		}
-
-		if (!FindRoutingConfigSDI(swf, mode,
-					  NTV2_IS_FBF_RGB(props.pixelFormat),
-					  props.deviceID, rc)) {
-			blog(LOG_DEBUG,
-			     "Could not find RoutingConfig for SDI Wire Format!");
+		VPIDStandard vpidStandard = DetermineVPIDStandard(
+			deviceID, props.ioSelect, props.videoFormat,
+			props.pixelFormat, props.sdiTransport,
+			props.sdi4kTransport);
+		if (!rc.FindFirstPreset(ConnectionKind::SDI, props.deviceID,
+					NTV2_MODE_DISPLAY, props.videoFormat,
+					props.pixelFormat, vpidStandard, rp)) {
+			blog(LOG_WARNING,
+			     "No SDI output routing preset found!");
 			return false;
 		}
 	} else if (NTV2_OUTPUT_DEST_IS_HDMI(init_dest)) {
 		HDMIWireFormat hwf = HDMIWireFormat::Unknown;
-
 		// special case devices...
 		if (props.deviceID == DEVICE_ID_TTAP_PRO) {
 			hwf = HDMIWireFormat::TTAP_PRO;
@@ -627,20 +369,22 @@ bool Routing::ConfigureOutputRoute(const OutputProps &props, NTV2Mode mode,
 				}
 			}
 		}
-
-		if (!FindRoutingConfigHDMI(hwf, mode,
-					   NTV2_IS_FBF_RGB(props.pixelFormat),
-					   props.deviceID, rc)) {
-			blog(LOG_DEBUG,
-			     "Could not find RoutingConfig for HDMI Wire Format!");
+		if (!rc.FindFirstPreset(ConnectionKind::HDMI, props.deviceID,
+					NTV2_MODE_DISPLAY, props.videoFormat,
+					props.pixelFormat, VPIDStandard_Unknown,
+					rp)) {
+			blog(LOG_WARNING,
+			     "No HDMI output routing preset found!");
 			return false;
 		}
 	}
 
-	std::string route_string = rc.route_string;
+	LogRoutingPreset(rp);
+
+	std::string route_string = rp.route_string;
 
 	// Replace framestore channel placeholders
-	ULWord start_framestore_index = initial_framestore_output_index(
+	ULWord start_framestore_index = InitialFramestoreOutputIndex(
 		deviceID, props.ioSelect, init_channel);
 	for (ULWord c = 0; c < NTV2_MAX_NUM_CHANNELS; c++) {
 		std::string fs_channel_placeholder =
@@ -661,75 +405,58 @@ bool Routing::ConfigureOutputRoute(const OutputProps &props, NTV2Mode mode,
 	}
 
 	NTV2XptConnections cnx;
-	ParseRouteString(route_string, cnx);
+	if (!ParseRouteString(route_string, cnx))
+		return false;
+
 	card->ApplySignalRoute(cnx, false);
 
 	// Apply SDI widget settings
 	if (props.ioSelect != IOSelection::HDMIMonitorOut) {
 		start_channel_index = GetIndexForNTV2Channel(init_channel);
 		for (uint32_t i = (uint32_t)start_channel_index;
-		     i < (start_channel_index + rc.num_wires); i++) {
+		     i < (start_channel_index + rp.num_channels); i++) {
 			NTV2Channel channel = GetNTV2ChannelForIndex(i);
 			if (::NTV2DeviceHasBiDirectionalSDI(deviceID)) {
 				card->SetSDITransmitEnable(
 					channel, mode == NTV2_MODE_DISPLAY);
 			}
-			card->SetSDIOut3GEnable(channel, rc.enable_3g_out);
-			card->SetSDIOut3GbEnable(channel, rc.enable_3gb_out);
-			card->SetSDIOut6GEnable(channel, rc.enable_6g_out);
-			card->SetSDIOut12GEnable(channel, rc.enable_12g_out);
+			card->SetSDIOut3GEnable(channel,
+						rp.flags & kEnable3GOut);
+			card->SetSDIOut3GbEnable(channel,
+						 rp.flags & kEnable3GbOut);
+			card->SetSDIOut6GEnable(channel,
+						rp.flags & kEnable6GOut);
+			card->SetSDIOut12GEnable(channel,
+						 rp.flags & kEnable12GOut);
 			card->SetSDIInLevelBtoLevelAConversion(
-				(UWord)i, rc.convert_3g_in);
+				(UWord)i, rp.flags & kConvert3GIn);
 			card->SetSDIOutLevelAtoLevelBConversion(
-				(UWord)i, rc.convert_3g_out);
+				(UWord)i, rp.flags & kConvert3GOut);
 			card->SetSDIOutRGBLevelAConversion(
-				(UWord)i, rc.enable_rgb_3ga_convert);
+				(UWord)i, rp.flags & kConvert3GaRGBOut);
 		}
 	}
 
 	// Apply Framestore settings
-	start_framestore_index = initial_framestore_output_index(
+	start_framestore_index = InitialFramestoreOutputIndex(
 		deviceID, props.ioSelect, init_channel);
 	for (uint32_t i = (uint32_t)start_framestore_index;
-	     i < (start_framestore_index + rc.num_framestores); i++) {
+	     i < (start_framestore_index + rp.num_framestores); i++) {
 		NTV2Channel channel = GetNTV2ChannelForIndex(i);
 		card->EnableChannel(channel);
 		card->SetMode(channel, mode);
 		card->SetVANCMode(NTV2_VANCMODE_OFF, channel);
 		card->SetVideoFormat(props.videoFormat, false, false, channel);
 		card->SetFrameBufferFormat(channel, props.pixelFormat);
-		card->SetTsiFrameEnable(rc.enable_tsi, channel);
-		card->Set4kSquaresEnable(rc.enable_4k_squares, channel);
-		card->SetQuadQuadSquaresEnable(rc.enable_8k_squares, channel);
+		card->SetTsiFrameEnable(rp.flags & kEnable4KTSI, channel);
+		card->Set4kSquaresEnable(rp.flags & kEnable4KSquares, channel);
+		card->SetQuadQuadSquaresEnable(rp.flags & kEnable8KSquares,
+					       channel);
 	}
 
 	return true;
 }
 
-ULWord Routing::initial_framestore_output_index(NTV2DeviceID deviceID,
-						IOSelection io,
-						NTV2Channel init_channel)
-{
-	if (deviceID == DEVICE_ID_TTAP_PRO) {
-		return 0;
-	} else if (deviceID == DEVICE_ID_KONA1) {
-		return 1;
-	} else if (deviceID == DEVICE_ID_IO4K ||
-		   deviceID == DEVICE_ID_IO4KPLUS) {
-		// SDI Monitor output uses framestore 4
-		if (io == IOSelection::SDI5)
-			return 3;
-	}
-
-	// HDMI Monitor output uses framestore 4
-	if (io == IOSelection::HDMIMonitorOut) {
-		return 3;
-	}
-
-	return GetIndexForNTV2Channel(init_channel);
-}
-
-// Output Routing
 void Routing::ConfigureOutputAudio(const OutputProps &props, CNTV2Card *card)
 {
 	if (!card)
@@ -813,3 +540,60 @@ void Routing::ConfigureOutputAudio(const OutputProps &props, CNTV2Card *card)
 
 	card->StopAudioOutput(audioSys);
 }
+
+ULWord Routing::InitialFramestoreOutputIndex(NTV2DeviceID deviceID,
+					     IOSelection io,
+					     NTV2Channel init_channel)
+{
+	if (deviceID == DEVICE_ID_TTAP_PRO) {
+		return 0;
+	} else if (deviceID == DEVICE_ID_KONA1) {
+		return 1;
+	} else if (deviceID == DEVICE_ID_IO4K ||
+		   deviceID == DEVICE_ID_IO4KPLUS) {
+		// SDI Monitor output uses framestore 4
+		if (io == IOSelection::SDI5)
+			return 3;
+	}
+
+	// HDMI Monitor output uses framestore 4
+	if (io == IOSelection::HDMIMonitorOut) {
+		return 3;
+	}
+
+	return GetIndexForNTV2Channel(init_channel);
+}
+
+void Routing::LogRoutingPreset(const RoutingPreset &rp)
+{
+	auto hexStr = [&](uint8_t val) -> std::string {
+		std::stringstream ss;
+		ss << std::setfill('0') << std::setw(sizeof(uint8_t) * 2)
+		   << std::hex << (val | 0);
+		return ss.str();
+	};
+
+	std::stringstream ss;
+	ss << "[ AJA Crosspoint Routing Preset ]"
+	   << "\nPreset: " << rp.name;
+	if (rp.kind == ConnectionKind::SDI) {
+		ss << "\nVPID Standard: 0x"
+		   << hexStr(static_cast<uint8_t>(rp.vpid_standard));
+	}
+	ss << "\nMode: " << NTV2ModeToString(rp.mode)
+	   << "\nChannels: " << rp.num_channels
+	   << "\nFramestores: " << rp.num_framestores;
+
+	blog(LOG_INFO, ss.str().c_str());
+
+	if (rp.device_ids.size() > 0) {
+		ss.clear();
+		for (auto id : rp.device_ids) {
+			ss << " - " << NTV2DeviceIDToString(id) << "\n";
+		}
+		blog(LOG_INFO, "\nCompatible Device IDs: \n%s",
+		     ss.str().c_str());
+	}
+}
+
+} // aja

+ 11 - 83
plugins/aja/aja-routing.hpp

@@ -1,15 +1,16 @@
 #pragma once
+
 #include "aja-props.hpp"
+#include "aja-presets.hpp"
 
 #include <ajantv2/includes/ntv2enums.h>
+#include <ajantv2/includes/ntv2signalrouter.h>
 
-#include <iostream>
 #include <string>
-#include <map>
-#include <vector>
 
 class CNTV2Card;
 
+namespace aja {
 /* The AJA hardware and NTV2 SDK uses a concept called "Signal Routing" to connect high-level firmware
  * blocks known as "Widgets" to one another via "crosspoint" connections. This facilitates streaming
  * data from one Widget to another to achieve specific functionality.
@@ -41,99 +42,26 @@ struct RoutingConfig {
 		route_string; // signal routing shorthand string to parse into crosspoint connections
 };
 
-/* This table is used to correlate a particular "raster definition" (i.e. SD/HD/4K/etc.)
- * and SMPTE VPID transport byte (VPIDStandard) to an SDIWireFormat enum.
- * This allows mapping SDI video signals to the correct format, particularly in the case
- * where multiple SDI formats share the same VPID transport value.
- * For example: VPIDStandard_1080 (0x85) is used on the wire for both single-link (1x SDI wire)
- * 1080-line HD SDI video AND quad-link (4x SDI wires) UHD/4K "square-division" video.
- */
-using VPIDSpec = std::pair<RasterDefinition, VPIDStandard>;
-
-static inline const std::map<VPIDSpec, SDIWireFormat> kSDIWireFormats = {
-	{{RasterDefinition::SD, VPIDStandard_483_576}, SDIWireFormat::SD_ST352},
-	{{RasterDefinition::HD, VPIDStandard_720},
-	 SDIWireFormat::HD_720p_ST292},
-	{{RasterDefinition::HD, VPIDStandard_1080},
-	 SDIWireFormat::HD_1080_ST292},
-	{{RasterDefinition::HD, VPIDStandard_1080_DualLink},
-	 SDIWireFormat::HD_1080_ST372_Dual},
-	{{RasterDefinition::HD, VPIDStandard_720_3Ga},
-	 SDIWireFormat::HD_720p_ST425_3Ga},
-	{{RasterDefinition::HD, VPIDStandard_1080_3Ga},
-	 SDIWireFormat::HD_1080p_ST425_3Ga},
-	{{RasterDefinition::HD, VPIDStandard_1080_DualLink_3Gb},
-	 SDIWireFormat::HD_1080p_ST425_3Gb_DL},
-	{{RasterDefinition::HD, VPIDStandard_720_3Gb},
-	 SDIWireFormat::HD_720p_ST425_3Gb},
-	{{RasterDefinition::HD, VPIDStandard_1080_3Gb},
-	 SDIWireFormat::HD_1080p_ST425_3Gb},
-	{{RasterDefinition::HD, VPIDStandard_1080_Dual_3Ga},
-	 SDIWireFormat::HD_1080p_ST425_Dual_3Ga},
-	{{RasterDefinition::HD, VPIDStandard_1080_Dual_3Gb},
-	 SDIWireFormat::HD_1080p_ST425_Dual_3Gb},
-	{{RasterDefinition::UHD_4K, VPIDStandard_1080_3Gb},
-	 SDIWireFormat::UHD4K_ST292_Dual_1_5_Squares},
-	{{RasterDefinition::UHD_4K, VPIDStandard_1080},
-	 SDIWireFormat::UHD4K_ST292_Quad_1_5_Squares},
-	{{RasterDefinition::UHD_4K, VPIDStandard_1080_3Ga},
-	 SDIWireFormat::UHD4K_ST425_Quad_3Ga_Squares},
-	{{RasterDefinition::UHD_4K, VPIDStandard_1080_DualLink_3Gb},
-	 SDIWireFormat::UHD4K_ST425_Quad_3Gb_Squares},
-	{{RasterDefinition::UHD_4K, VPIDStandard_2160_DualLink},
-	 SDIWireFormat::UHD4K_ST425_Dual_3Gb_2SI},
-	{{RasterDefinition::UHD_4K, VPIDStandard_2160_QuadLink_3Ga},
-	 SDIWireFormat::UHD4K_ST425_Quad_3Ga_2SI},
-	{{RasterDefinition::UHD_4K, VPIDStandard_2160_QuadDualLink_3Gb},
-	 SDIWireFormat::UHD4K_ST425_Quad_3Gb_2SI},
-	{{RasterDefinition::UHD_4K, VPIDStandard_2160_Single_6Gb},
-	 SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI},
-	{{RasterDefinition::UHD_4K_Retail_12G, VPIDStandard_2160_Single_6Gb},
-	 SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI_Kona5_io4KPlus},
-	{{RasterDefinition::UHD_4K, VPIDStandard_2160_Single_12Gb},
-	 SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI},
-	{{RasterDefinition::UHD_4K_Retail_12G, VPIDStandard_2160_Single_12Gb},
-	 SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI_Kona5_io4KPlus},
-	{{RasterDefinition::UHD2_8K, VPIDStandard_4320_DualLink_12Gb},
-	 SDIWireFormat::UHD28K_ST2082_Dual_12G},
-	{{RasterDefinition::UHD2_8K, VPIDStandard_2160_DualLink_12Gb},
-	 SDIWireFormat::UHD28K_ST2082_RGB_Dual_12G},
-	{{RasterDefinition::UHD2_8K, VPIDStandard_4320_QuadLink_12Gb},
-	 SDIWireFormat::UHD28K_ST2082_Quad_12G},
-};
-
-extern RasterDefinition
-GetRasterDefinition(IOSelection io, NTV2VideoFormat vf,
-		    NTV2DeviceID deviceID = DEVICE_ID_NOTFOUND);
-
-extern std::string RasterDefinitionToString(RasterDefinition rd);
-
 // Applies RoutingConfig settings to the card to configure a specific SDI/HDMI capture/output mode.
 class Routing {
 public:
 	static bool ParseRouteString(const std::string &route,
 				     NTV2XptConnections &cnx);
-	static bool DetermineSDIWireFormat(NTV2DeviceID deviceID, VPIDSpec spec,
-					   SDIWireFormat &swf);
-	static bool FindRoutingConfigHDMI(HDMIWireFormat hwf, NTV2Mode mode,
-					  bool isRGB, NTV2DeviceID deviceID,
-					  RoutingConfig &routing);
-	static bool FindRoutingConfigSDI(SDIWireFormat swf, NTV2Mode mode,
-					 bool isRGB, NTV2DeviceID deviceID,
-					 RoutingConfig &routing);
 
 	static void StartSourceAudio(const SourceProps &props, CNTV2Card *card);
-
 	static void StopSourceAudio(const SourceProps &props, CNTV2Card *card);
 
 	static bool ConfigureSourceRoute(const SourceProps &props,
 					 NTV2Mode mode, CNTV2Card *card);
 	static bool ConfigureOutputRoute(const OutputProps &props,
 					 NTV2Mode mode, CNTV2Card *card);
-	static ULWord initial_framestore_output_index(NTV2DeviceID deviceID,
-						      IOSelection io,
-						      NTV2Channel init_channel);
-
 	static void ConfigureOutputAudio(const OutputProps &props,
 					 CNTV2Card *card);
+
+	static ULWord InitialFramestoreOutputIndex(NTV2DeviceID deviceID,
+						   IOSelection io,
+						   NTV2Channel init_channel);
+	static void LogRoutingPreset(const RoutingPreset &rp);
 };
+
+} // aja

+ 91 - 127
plugins/aja/aja-source.cpp

@@ -10,6 +10,7 @@
 #include <obs-module.h>
 
 #include <ajantv2/includes/ntv2card.h>
+#include <ajantv2/includes/ntv2utils.h>
 
 #define NTV2_AUDIOSIZE_MAX (401 * 1024)
 
@@ -73,10 +74,8 @@ std::string AJASource::GetName() const
 void populate_source_device_list(obs_property_t *list)
 {
 	obs_property_list_clear(list);
-
 	auto &cardManager = aja::CardManager::Instance();
 	cardManager.EnumerateCards();
-
 	for (const auto &iter : cardManager.GetCardEntries()) {
 		if (iter.second) {
 			CNTV2Card *card = iter.second->GetCard();
@@ -117,11 +116,9 @@ static void ResetAudioBufferOffsets(CNTV2Card *card,
 	offsets.readOffset = 0;
 	offsets.wrapAddress = 0;
 	offsets.bytesRead = 0;
-
 	card->GetAudioReadOffset(offsets.readOffset, audioSystem);
 	card->GetAudioWrapAddress(offsets.wrapAddress, audioSystem);
 	offsets.wrapAddress += offsets.readOffset;
-
 	offsets.lastAddress = offsets.readOffset;
 }
 
@@ -130,7 +127,6 @@ void AJASource::GenerateTestPattern(NTV2VideoFormat vf, NTV2PixelFormat pf,
 {
 	NTV2VideoFormat vid_fmt = vf;
 	NTV2PixelFormat pix_fmt = pf;
-
 	if (vid_fmt == NTV2_FORMAT_UNKNOWN)
 		vid_fmt = NTV2_FORMAT_720p_5994;
 	if (pix_fmt == NTV2_FBF_INVALID)
@@ -138,17 +134,14 @@ void AJASource::GenerateTestPattern(NTV2VideoFormat vf, NTV2PixelFormat pf,
 
 	NTV2FormatDesc fd(vid_fmt, pix_fmt, NTV2_VANCMODE_OFF);
 	auto bufSize = fd.GetTotalRasterBytes();
-
 	if (bufSize != mTestPattern.size()) {
 		mTestPattern.clear();
 		mTestPattern.resize(bufSize);
-
 		NTV2TestPatternGen gen;
 		gen.DrawTestPattern(ps, fd.GetRasterWidth(),
 				    fd.GetRasterHeight(), pix_fmt,
 				    mTestPattern);
 	}
-
 	if (mTestPattern.size() == 0) {
 		blog(LOG_DEBUG,
 		     "AJASource::GenerateTestPattern: Error generating test pattern!");
@@ -163,13 +156,12 @@ void AJASource::GenerateTestPattern(NTV2VideoFormat vf, NTV2PixelFormat pf,
 	obsFrame.format = aja::AJAPixelFormatToOBSVideoFormat(pix_fmt);
 	obsFrame.data[0] = mTestPattern.data();
 	obsFrame.linesize[0] = fd.GetBytesPerRow();
-
 	video_format_get_parameters(VIDEO_CS_DEFAULT, VIDEO_RANGE_FULL,
 				    obsFrame.color_matrix,
 				    obsFrame.color_range_min,
 				    obsFrame.color_range_max);
-
 	obs_source_output_video2(mSource, &obsFrame);
+	blog(LOG_DEBUG, "AJASource::GenerateTestPattern: Black");
 }
 
 void AJASource::CaptureThread(AJAThread *thread, void *data)
@@ -195,9 +187,9 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 	}
 
 	auto sourceProps = ajaSource->GetSourceProps();
+	auto inputSource = sourceProps.InitialInputSource();
 	auto channel = sourceProps.Channel();
 	auto audioSystem = sourceProps.AudioSystem();
-
 	// Current "on-air" frame on the card. The capture thread "Ping-pongs" between
 	// two frames, starting at an index corresponding to the framestore channel.
 	// For example:
@@ -221,26 +213,21 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 	while (ajaSource->IsCapturing()) {
 		if (card->GetModelName() == "(Not Found)") {
 			os_sleep_ms(250);
-
 			obs_source_update(ajaSource->mSource, settings);
-
 			break;
 		}
 
+		auto videoFormat = sourceProps.videoFormat;
+		auto pixelFormat = sourceProps.pixelFormat;
+		auto ioSelection = sourceProps.ioSelect;
 		bool audioOverrun = false;
 
 		card->WaitForInputFieldID(NTV2_FIELD0, channel);
-
 		currentCardFrame ^= 1;
 
-		auto videoFormat = sourceProps.videoFormat;
-		auto pixelFormat = sourceProps.pixelFormat;
-
 		// Card format detection -- restarts capture thread via aja_source_update callback
 		auto newVideoFormat = card->GetInputVideoFormat(
-			sourceProps.inputSource,
-			aja::Is3GLevelB(card, channel));
-
+			inputSource, aja::Is3GLevelB(card, channel));
 		if (newVideoFormat == NTV2_FORMAT_UNKNOWN) {
 			blog(LOG_DEBUG,
 			     "AJASource::CaptureThread: Video format unknown!");
@@ -250,6 +237,9 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 			continue;
 		}
 
+		newVideoFormat = aja::HandleSpecialCaseFormats(
+			ioSelection, newVideoFormat, sourceProps.deviceID);
+
 		if (sourceProps.autoDetect && (videoFormat != newVideoFormat)) {
 			blog(LOG_INFO,
 			     "AJASource::CaptureThread: New Video Format detected! Triggering 'aja_source_update' callback and returning...");
@@ -258,33 +248,26 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 			     NTV2VideoFormatToString(videoFormat, true).c_str(),
 			     NTV2VideoFormatToString(newVideoFormat, true)
 				     .c_str());
-
 			os_sleep_ms(250);
-
 			obs_source_update(ajaSource->mSource, settings);
-
 			break;
 		}
 
 		card->ReadAudioLastIn(offsets.currentAddress, audioSystem);
 		offsets.currentAddress &= ~0x3; // Force DWORD alignment
 		offsets.currentAddress += offsets.readOffset;
-
 		if (offsets.currentAddress < offsets.lastAddress) {
 			offsets.bytesRead =
 				offsets.wrapAddress - offsets.lastAddress;
 
 			if (offsets.bytesRead >
 			    ajaSource->mAudioBuffer.GetByteCount()) {
-
 				blog(LOG_DEBUG,
 				     "AJASource::CaptureThread: Audio overrun (1)! Buffer Size: %d, Bytes Captured: %d",
 				     ajaSource->mAudioBuffer.GetByteCount(),
 				     offsets.bytesRead);
-
 				ResetAudioBufferOffsets(card, audioSystem,
 							offsets);
-
 				audioOverrun = true;
 			}
 
@@ -293,7 +276,6 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 						   ajaSource->mAudioBuffer,
 						   offsets.lastAddress,
 						   offsets.bytesRead);
-
 				card->DMAReadAudio(
 					audioSystem,
 					reinterpret_cast<ULWord *>(
@@ -303,42 +285,33 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 					offsets.readOffset,
 					offsets.currentAddress -
 						offsets.readOffset);
-
 				offsets.bytesRead += offsets.currentAddress -
 						     offsets.readOffset;
 			}
 
 			if (offsets.bytesRead >
 			    ajaSource->mAudioBuffer.GetByteCount()) {
-
 				blog(LOG_DEBUG,
 				     "AJASource::CaptureThread: Audio overrun (2)! Buffer Size: %d, Bytes Captured: %d",
 				     ajaSource->mAudioBuffer.GetByteCount(),
 				     offsets.bytesRead);
-
 				ResetAudioBufferOffsets(card, audioSystem,
 							offsets);
-
 				audioOverrun = true;
 			}
 		} else {
 			offsets.bytesRead =
 				offsets.currentAddress - offsets.lastAddress;
-
 			if (offsets.bytesRead >
 			    ajaSource->mAudioBuffer.GetByteCount()) {
-
 				blog(LOG_DEBUG,
 				     "AJASource::CaptureThread: Audio overrun (3)! Buffer Size: %d, Bytes Captured: %d",
 				     ajaSource->mAudioBuffer.GetByteCount(),
 				     offsets.bytesRead);
-
 				ResetAudioBufferOffsets(card, audioSystem,
 							offsets);
-
 				audioOverrun = true;
 			}
-
 			if (!audioOverrun) {
 				card->DMAReadAudio(audioSystem,
 						   ajaSource->mAudioBuffer,
@@ -349,7 +322,6 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 
 		if (!audioOverrun) {
 			offsets.lastAddress = offsets.currentAddress;
-
 			obs_source_audio audioPacket;
 			audioPacket.samples_per_sec = 48000;
 			audioPacket.format = AUDIO_FORMAT_32BIT;
@@ -358,7 +330,6 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 			audioPacket.timestamp = os_gettime_ns();
 			audioPacket.data[0] = (uint8_t *)ajaSource->mAudioBuffer
 						      .GetHostPointer();
-
 			obs_source_output_audio(ajaSource->mSource,
 						&audioPacket);
 		}
@@ -378,7 +349,6 @@ void AJASource::CaptureThread(AJAThread *thread, void *data)
 				videoFormat);
 
 		NTV2FormatDesc fd(actualVideoFormat, pixelFormat);
-
 		struct obs_source_frame2 obsFrame;
 		obsFrame.flip = false;
 		obsFrame.timestamp = os_gettime_ns();
@@ -497,18 +467,22 @@ bool AJASource::ReadChannelVPIDs(NTV2Channel channel, VPIDData &vpids)
 	return read_ok;
 }
 
-bool AJASource::ReadWireFormats(NTV2DeviceID device_id,
-				const NTV2InputSourceSet &srcs,
+bool AJASource::ReadWireFormats(NTV2DeviceID device_id, IOSelection io_select,
 				NTV2VideoFormat &vf, NTV2PixelFormat &pf,
 				VPIDDataList &vpids)
 {
-	if (srcs.empty())
+	NTV2InputSourceSet input_srcs;
+	aja::IOSelectionToInputSources(io_select, input_srcs);
+	if (input_srcs.empty()) {
+		blog(LOG_INFO,
+		     "AJASource::ReadWireFormats: No NTV2InputSources found for IOSelection %s",
+		     aja::IOSelectionToString(io_select).c_str());
 		return false;
+	}
 
-	NTV2InputSource initial_src = *srcs.begin();
-	for (auto &&src : srcs) {
+	NTV2InputSource initial_src = *input_srcs.begin();
+	for (auto &&src : input_srcs) {
 		auto channel = NTV2InputSourceToChannel(src);
-
 		mCard->EnableChannel(channel);
 		if (NTV2_INPUT_SOURCE_IS_SDI(src)) {
 			if (NTV2DeviceHasBiDirectionalSDI(device_id)) {
@@ -567,6 +541,8 @@ bool AJASource::ReadWireFormats(NTV2DeviceID device_id,
 		}
 	}
 
+	vf = aja::HandleSpecialCaseFormats(io_select, vf, device_id);
+
 	blog(LOG_INFO, "AJASource::ReadWireFormats - Detected video format %s",
 	     NTV2VideoFormatToString(vf).c_str());
 
@@ -625,11 +601,13 @@ bool aja_source_device_changed(void *data, obs_properties_t *props,
 		return false;
 	}
 
-	auto &cardManager = aja::CardManager::Instance();
-
 	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
+	if (!cardID)
+		return false;
+
+	auto &cardManager = aja::CardManager::Instance();
 	auto cardEntry = cardManager.GetCardEntry(cardID);
-	if (!cardID || !cardEntry) {
+	if (!cardEntry) {
 		blog(LOG_DEBUG,
 		     "aja_source_device_changed: Card Entry not found for %s",
 		     cardID);
@@ -663,17 +641,28 @@ bool aja_source_device_changed(void *data, obs_properties_t *props,
 		obs_properties_get(props, kUIPropVideoFormatSelect.id);
 	obs_property_t *pix_fmt_list =
 		obs_properties_get(props, kUIPropPixelFormatSelect.id);
+	obs_property_t *sdi_trx_list =
+		obs_properties_get(props, kUIPropSDITransport.id);
 	obs_property_t *sdi_4k_list =
-		obs_properties_get(props, kUIPropSDI4KTransport.id);
+		obs_properties_get(props, kUIPropSDITransport4K.id);
 
 	obs_property_list_clear(vid_fmt_list);
-	obs_property_list_add_int(vid_fmt_list, "Auto", kVideoFormatAuto);
+	obs_property_list_add_int(vid_fmt_list, obs_module_text("Auto"),
+				  kAutoDetect);
 	populate_video_format_list(deviceID, vid_fmt_list, videoFormatChannel1);
 
 	obs_property_list_clear(pix_fmt_list);
-	obs_property_list_add_int(pix_fmt_list, "Auto", kPixelFormatAuto);
+	obs_property_list_add_int(pix_fmt_list, obs_module_text("Auto"),
+				  kAutoDetect);
 	populate_pixel_format_list(deviceID, pix_fmt_list);
 
+	IOSelection io_select = static_cast<IOSelection>(
+		obs_data_get_int(settings, kUIPropInput.id));
+	obs_property_list_clear(sdi_trx_list);
+	obs_property_list_add_int(sdi_trx_list, obs_module_text("Auto"),
+				  kAutoDetect);
+	populate_sdi_transport_list(sdi_trx_list, io_select);
+
 	obs_property_list_clear(sdi_4k_list);
 	populate_sdi_4k_transport_list(sdi_4k_list);
 
@@ -706,8 +695,11 @@ bool aja_io_selection_changed(void *data, obs_properties_t *props,
 		return false;
 	}
 
-	auto &cardManager = aja::CardManager::Instance();
 	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
+	if (!cardID)
+		return false;
+
+	auto &cardManager = aja::CardManager::Instance();
 	auto cardEntry = cardManager.GetCardEntry(cardID);
 	if (!cardEntry) {
 		blog(LOG_DEBUG,
@@ -770,7 +762,8 @@ void aja_source_destroy(void *data)
 	CNTV2Card *card = ajaSource->GetCard();
 	if (card) {
 		deviceID = card->GetDeviceID();
-		Routing::StopSourceAudio(ajaSource->GetSourceProps(), card);
+		aja::Routing::StopSourceAudio(ajaSource->GetSourceProps(),
+					      card);
 	}
 
 	ajaSource->mVideoBuffer.Deallocate();
@@ -779,9 +772,7 @@ void aja_source_destroy(void *data)
 	ajaSource->mAudioBuffer = NULL;
 
 	auto &cardManager = aja::CardManager::Instance();
-
 	const auto &cardID = ajaSource->CardID();
-
 	auto cardEntry = cardManager.GetCardEntry(cardID);
 	if (!cardEntry) {
 		blog(LOG_DEBUG,
@@ -863,30 +854,29 @@ static void aja_source_update(void *data, obs_data_t *settings)
 		return;
 	}
 
-	const std::string &wantCardID =
-		obs_data_get_string(settings, kUIPropDevice.id);
-	const std::string &currentCardID = ajaSource->CardID();
-
 	auto io_select = static_cast<IOSelection>(
 		obs_data_get_int(settings, kUIPropInput.id));
 	auto vf_select = static_cast<NTV2VideoFormat>(
 		obs_data_get_int(settings, kUIPropVideoFormatSelect.id));
 	auto pf_select = static_cast<NTV2PixelFormat>(
 		obs_data_get_int(settings, kUIPropPixelFormatSelect.id));
-	auto t4_select = static_cast<SDI4KTransport>(
-		obs_data_get_int(settings, kUIPropSDI4KTransport.id));
+	auto sdi_trx_select = static_cast<SDITransport>(
+		obs_data_get_int(settings, kUIPropSDITransport.id));
+	auto sdi_t4k_select = static_cast<SDITransport4K>(
+		obs_data_get_int(settings, kUIPropSDITransport4K.id));
 	bool deactivateWhileNotShowing =
 		obs_data_get_bool(settings, kUIPropDeactivateWhenNotShowing.id);
+	const std::string &wantCardID =
+		obs_data_get_string(settings, kUIPropDevice.id);
 
-	auto &cardManager = aja::CardManager::Instance();
-
-	cardManager.EnumerateCards();
-
+	const std::string &currentCardID = ajaSource->CardID();
 	if (wantCardID != currentCardID) {
 		initialized = false;
 		ajaSource->Deactivate();
 	}
 
+	auto &cardManager = aja::CardManager::Instance();
+	cardManager.EnumerateCards();
 	auto cardEntry = cardManager.GetCardEntry(wantCardID);
 	if (!cardEntry) {
 		blog(LOG_DEBUG,
@@ -894,7 +884,6 @@ static void aja_source_update(void *data, obs_data_t *settings)
 		     wantCardID.c_str());
 		return;
 	}
-
 	CNTV2Card *card = cardEntry->GetCard();
 	if (!card || !card->IsOpen()) {
 		blog(LOG_ERROR, "aja_source_update: AJA device %s not open!",
@@ -907,7 +896,6 @@ static void aja_source_update(void *data, obs_data_t *settings)
 		     wantCardID.c_str());
 		return;
 	}
-
 	ajaSource->SetCard(cardEntry->GetCard());
 
 	SourceProps curr_props = ajaSource->GetSourceProps();
@@ -941,37 +929,31 @@ static void aja_source_update(void *data, obs_data_t *settings)
 		return;
 	}
 
-	NTV2InputSourceSet input_srcs;
-	aja::IOSelectionToInputSources(io_select, input_srcs);
-	if (input_srcs.empty()) {
-		blog(LOG_INFO,
-		     "aja_source_update: No NTV2InputSources found for IOSelection %s",
-		     aja::IOSelectionToString(io_select).c_str());
-		return;
-	}
-
 	SourceProps want_props;
 	want_props.deviceID = card->GetDeviceID();
 	want_props.ioSelect = io_select;
-	want_props.inputSource = *input_srcs.begin();
 	want_props.videoFormat =
-		((int32_t)vf_select == kVideoFormatAuto)
+		((int32_t)vf_select == kAutoDetect)
 			? NTV2_FORMAT_UNKNOWN
 			: static_cast<NTV2VideoFormat>(vf_select);
 	want_props.pixelFormat =
-		((int32_t)pf_select == kPixelFormatAuto)
+		((int32_t)pf_select == kAutoDetect)
 			? NTV2_FBF_INVALID
 			: static_cast<NTV2PixelFormat>(pf_select);
-	want_props.sdi4kTransport = t4_select;
+	want_props.sdiTransport =
+		((int32_t)sdi_trx_select == kAutoDetect)
+			? SDITransport::Unknown
+			: static_cast<SDITransport>(sdi_trx_select);
+	want_props.sdi4kTransport = sdi_t4k_select;
 	want_props.vpids.clear();
 	want_props.deactivateWhileNotShowing = deactivateWhileNotShowing;
-	want_props.autoDetect = ((int32_t)vf_select == kVideoFormatAuto ||
-				 (int32_t)pf_select == kPixelFormatAuto);
+	want_props.autoDetect = ((int32_t)vf_select == kAutoDetect ||
+				 (int32_t)pf_select == kAutoDetect);
 	ajaSource->SetCardID(wantCardID);
 	ajaSource->SetDeviceIndex((UWord)cardEntry->GetCardIndex());
 
 	if (NTV2_IS_4K_VIDEO_FORMAT(want_props.videoFormat) &&
-	    want_props.sdi4kTransport == SDI4KTransport::Squares) {
+	    want_props.sdi4kTransport == SDITransport4K::Squares) {
 		if (want_props.ioSelect == IOSelection::SDI1_2) {
 			want_props.ioSelect = IOSelection::SDI1_2_Squares;
 		} else if (want_props.ioSelect == IOSelection::SDI3_4) {
@@ -1009,21 +991,20 @@ static void aja_source_update(void *data, obs_data_t *settings)
 	// Read SDI video payload IDs (VPID) used for helping to determine the wire format
 	NTV2VideoFormat new_vf = want_props.videoFormat;
 	NTV2PixelFormat new_pf = want_props.pixelFormat;
-	if (!ajaSource->ReadWireFormats(want_props.deviceID, input_srcs, new_vf,
-					new_pf, want_props.vpids)) {
+	if (!ajaSource->ReadWireFormats(want_props.deviceID,
+					want_props.ioSelect, new_vf, new_pf,
+					want_props.vpids)) {
 		blog(LOG_ERROR, "aja_source_update: ReadWireFormats failed!");
-
 		cardEntry->ReleaseInputSelection(want_props.ioSelect,
 						 curr_props.deviceID,
 						 ajaSource->GetName());
-
 		return;
 	}
 
 	// Set auto-detected formats
-	if ((int32_t)vf_select == kVideoFormatAuto)
+	if ((int32_t)vf_select == kAutoDetect)
 		want_props.videoFormat = new_vf;
-	if ((int32_t)pf_select == kPixelFormatAuto)
+	if ((int32_t)pf_select == kAutoDetect)
 		want_props.pixelFormat = new_pf;
 
 	if (want_props.videoFormat == NTV2_FORMAT_UNKNOWN ||
@@ -1033,66 +1014,51 @@ static void aja_source_update(void *data, obs_data_t *settings)
 		     NTV2VideoFormatToString(want_props.videoFormat).c_str(),
 		     NTV2FrameBufferFormatToString(want_props.pixelFormat)
 			     .c_str());
-
 		cardEntry->ReleaseInputSelection(want_props.ioSelect,
 						 curr_props.deviceID,
 						 ajaSource->GetName());
-
 		return;
 	}
 
 	// Change capture format and restart capture thread
 	if (!initialized || want_props != ajaSource->GetSourceProps()) {
-		Routing::ConfigureSourceRoute(want_props, NTV2_MODE_CAPTURE,
-					      card);
-
+		aja::Routing::ConfigureSourceRoute(want_props,
+						   NTV2_MODE_CAPTURE, card);
 		ajaSource->Deactivate();
-
 		initialized = true;
 	}
 
 	ajaSource->SetSourceProps(want_props);
-
 	ajaSource->ResetVideoBuffer(want_props.videoFormat,
 				    want_props.pixelFormat);
-
-	Routing::StartSourceAudio(want_props, card);
-
+	aja::Routing::StartSourceAudio(want_props, card);
 	card->SetReference(NTV2_REFERENCE_FREERUN);
-
 	ajaSource->Activate(true);
 }
 
 static obs_properties_t *aja_source_get_properties(void *data)
 {
 	obs_properties_t *props = obs_properties_create();
-
-	// Uncomment below to only update when the user presses OK or Apply
-	// obs_properties_set_flags(props, OBS_PROPERTIES_DEFER_UPDATE);
-
 	obs_property_t *device_list = obs_properties_add_list(
 		props, kUIPropDevice.id, obs_module_text(kUIPropDevice.text),
 		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
-
 	populate_source_device_list(device_list);
-
 	obs_property_t *io_select_list = obs_properties_add_list(
 		props, kUIPropInput.id, obs_module_text(kUIPropInput.text),
 		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
 	obs_property_t *vid_fmt_list = obs_properties_add_list(
 		props, kUIPropVideoFormatSelect.id,
 		obs_module_text(kUIPropVideoFormatSelect.text),
 		OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
 	obs_properties_add_list(props, kUIPropPixelFormatSelect.id,
 				obs_module_text(kUIPropPixelFormatSelect.text),
 				OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
-	obs_properties_add_list(props, kUIPropSDI4KTransport.id,
-				obs_module_text(kUIPropSDI4KTransport.text),
+	obs_properties_add_list(props, kUIPropSDITransport.id,
+				obs_module_text(kUIPropSDITransport.text),
+				OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
+	obs_properties_add_list(props, kUIPropSDITransport4K.id,
+				obs_module_text(kUIPropSDITransport4K.text),
 				OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
-
 	obs_properties_add_bool(
 		props, kUIPropDeactivateWhenNotShowing.id,
 		obs_module_text(kUIPropDeactivateWhenNotShowing.text));
@@ -1111,26 +1077,21 @@ void aja_source_get_defaults(obs_data_t *settings)
 {
 	obs_data_set_default_int(settings, kUIPropInput.id,
 				 static_cast<long long>(IOSelection::Invalid));
-
 	obs_data_set_default_int(settings, kUIPropVideoFormatSelect.id,
-				 static_cast<long long>(kVideoFormatAuto));
-
+				 static_cast<long long>(kAutoDetect));
+	obs_data_set_default_int(settings, kUIPropPixelFormatSelect.id,
+				 static_cast<long long>(kAutoDetect));
+	obs_data_set_default_int(settings, kUIPropSDITransport.id,
+				 static_cast<long long>(kAutoDetect));
 	obs_data_set_default_int(
-		settings, kUIPropPixelFormatSelect.id,
-		static_cast<long long>(kDefaultAJAPixelFormat));
-
-	obs_data_set_default_int(
-		settings, kUIPropSDI4KTransport.id,
-		static_cast<long long>(SDI4KTransport::TwoSampleInterleave));
-
+		settings, kUIPropSDITransport4K.id,
+		static_cast<long long>(SDITransport4K::TwoSampleInterleave));
 	obs_data_set_default_bool(settings, kUIPropDeactivateWhenNotShowing.id,
 				  false);
 }
 
 void aja_source_save(void *data, obs_data_t *settings)
 {
-	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
-
 	AJASource *ajaSource = (AJASource *)data;
 	if (!ajaSource) {
 		blog(LOG_ERROR,
@@ -1138,9 +1099,13 @@ void aja_source_save(void *data, obs_data_t *settings)
 		return;
 	}
 
+	const char *cardID = obs_data_get_string(settings, kUIPropDevice.id);
+	if (!cardID)
+		return;
+
 	auto &cardManager = aja::CardManager::Instance();
 	auto cardEntry = cardManager.GetCardEntry(cardID);
-	if (!cardID || !cardEntry) {
+	if (!cardEntry) {
 		blog(LOG_DEBUG, "aja_source_save: Card Entry not found for %s",
 		     cardID);
 		return;
@@ -1176,6 +1141,5 @@ struct obs_source_info create_aja_source_info()
 	aja_source_info.get_defaults = aja_source_get_defaults;
 	aja_source_info.save = aja_source_save;
 	aja_source_info.icon_type = OBS_ICON_TYPE_CAMERA;
-
 	return aja_source_info;
 }

+ 1 - 2
plugins/aja/aja-source.hpp

@@ -50,8 +50,7 @@ public:
 
 	bool ReadChannelVPIDs(NTV2Channel channel, VPIDData &vpids);
 
-	bool ReadWireFormats(NTV2DeviceID device_id,
-			     const NTV2InputSourceSet &srcs,
+	bool ReadWireFormats(NTV2DeviceID device_id, IOSelection io_select,
 			     NTV2VideoFormat &vf, NTV2PixelFormat &pf,
 			     VPIDDataList &vpids);
 

+ 32 - 14
plugins/aja/aja-ui-props.hpp

@@ -13,13 +13,13 @@ struct UIProperty {
 
 static const UIProperty kUIPropCaptureModule = {
 	"aja_source",
-	obs_module_text("AJACapture.Device"),
+	"AJACapture.Device",
 	"",
 };
 
 static const UIProperty kUIPropOutputModule = {
 	"aja_output",
-	obs_module_text("AJAOutput.Device"),
+	"AJAOutput.Device",
 	"",
 };
 
@@ -35,57 +35,75 @@ static const UIProperty kUIPropAJAOutputID = {
 
 static const UIProperty kUIPropDevice = {
 	"ui_prop_device",
-	obs_module_text("Device"),
+	"Device",
 	"",
 };
 
 static const UIProperty kUIPropOutput = {
 	"ui_prop_output",
-	obs_module_text("Output"),
+	"Output",
 	"",
 };
 
 static const UIProperty kUIPropInput = {
 	"ui_prop_input",
-	obs_module_text("Input"),
+	"Input",
 	"",
 };
 
-static const UIProperty kUIPropIOSelect = {"ui_prop_select_input",
-					   obs_module_text("IOSelect"), ""};
+static const UIProperty kUIPropIOSelect = {"ui_prop_select_input", "IOSelect",
+					   ""};
 
-static const UIProperty kUIPropSDI4KTransport = {
+static const UIProperty kUIPropSDITransport = {
 	"ui_prop_sdi_transport",
-	obs_module_text("SDI4KTransport"),
+	"SDITransport",
+	"",
+};
+
+static const UIProperty kUIPropSDITransport4K = {
+	"ui_prop_sdi_transport_4k",
+	"SDITransport4K",
 	"",
 };
 
 static const UIProperty kUIPropVideoFormatSelect = {
 	"ui_prop_vid_fmt",
-	obs_module_text("VideoFormat"),
+	"VideoFormat",
 	"",
 };
 
 static const UIProperty kUIPropPixelFormatSelect = {
 	"ui_prop_pix_fmt",
-	obs_module_text("PixelFormat"),
+	"PixelFormat",
 	"",
 };
 
 static const UIProperty kUIPropAutoStartOutput = {
 	"ui_prop_auto_start_output",
-	obs_module_text("AutoStart"),
+	"AutoStart",
 	"",
 };
 
 static const UIProperty kUIPropDeactivateWhenNotShowing = {
 	"ui_prop_deactivate_when_not_showing",
-	obs_module_text("DeactivateWhenNotShowing"),
+	"DeactivateWhenNotShowing",
 	"",
 };
 
 static const UIProperty kUIPropBuffering = {
 	"ui_prop_buffering",
-	obs_module_text("Buffering"),
+	"Buffering",
+	"",
+};
+
+static const UIProperty kUIPropMultiViewEnable = {
+	"ui_prop_multi_view_enable",
+	"Enable Multi View",
 	"",
 };
+
+static const UIProperty kUIPropMultiViewAudioSource = {
+	"ui_prop_multi_view_audio_source",
+	"Multi View Audio Source",
+	"",
+};

+ 113 - 0
plugins/aja/aja-vpid-data.cpp

@@ -0,0 +1,113 @@
+#include "aja-vpid-data.hpp"
+
+VPIDData::VPIDData()
+	: mVpidA{0},
+	  mVpidB{0},
+	  mStandardA{VPIDStandard_Unknown},
+	  mStandardB{VPIDStandard_Unknown},
+	  mSamplingA{VPIDSampling_XYZ_444},
+	  mSamplingB{VPIDSampling_XYZ_444}
+{
+}
+
+VPIDData::VPIDData(ULWord vpidA, ULWord vpidB)
+	: mVpidA{vpidA},
+	  mVpidB{vpidB},
+	  mStandardA{VPIDStandard_Unknown},
+	  mStandardB{VPIDStandard_Unknown},
+	  mSamplingA{VPIDSampling_XYZ_444},
+	  mSamplingB{VPIDSampling_XYZ_444}
+{
+	Parse();
+}
+
+VPIDData::VPIDData(const VPIDData &other)
+	: mVpidA{other.mVpidA},
+	  mVpidB{other.mVpidB},
+	  mStandardA{VPIDStandard_Unknown},
+	  mStandardB{VPIDStandard_Unknown},
+	  mSamplingA{VPIDSampling_XYZ_444},
+	  mSamplingB{VPIDSampling_XYZ_444}
+{
+	Parse();
+}
+VPIDData::VPIDData(VPIDData &&other)
+	: mVpidA{other.mVpidA},
+	  mVpidB{other.mVpidB},
+	  mStandardA{VPIDStandard_Unknown},
+	  mStandardB{VPIDStandard_Unknown},
+	  mSamplingA{VPIDSampling_XYZ_444},
+	  mSamplingB{VPIDSampling_XYZ_444}
+{
+	Parse();
+}
+
+VPIDData &VPIDData::operator=(const VPIDData &other)
+{
+	mVpidA = other.mVpidA;
+	mVpidB = other.mVpidB;
+	return *this;
+}
+
+VPIDData &VPIDData::operator=(VPIDData &&other)
+{
+	mVpidA = other.mVpidA;
+	mVpidB = other.mVpidB;
+	return *this;
+}
+
+bool VPIDData::operator==(const VPIDData &rhs) const
+{
+	return (mVpidA == rhs.mVpidA && mVpidB == rhs.mVpidB);
+}
+
+bool VPIDData::operator!=(const VPIDData &rhs) const
+{
+	return !operator==(rhs);
+}
+
+void VPIDData::SetA(ULWord vpidA)
+{
+	mVpidA = vpidA;
+}
+
+void VPIDData::SetB(ULWord vpidB)
+{
+	mVpidB = vpidB;
+}
+
+void VPIDData::Parse()
+{
+	CNTV2VPID parserA;
+	parserA.SetVPID(mVpidA);
+	mStandardA = parserA.GetStandard();
+	mSamplingA = parserA.GetSampling();
+
+	CNTV2VPID parserB;
+	parserB.SetVPID(mVpidB);
+	mStandardB = parserB.GetStandard();
+	mSamplingB = parserB.GetSampling();
+}
+
+bool VPIDData::IsRGB() const
+{
+	switch (mSamplingA) {
+	default:
+		break;
+	case VPIDSampling_GBR_444:
+	case VPIDSampling_GBRA_4444:
+	case VPIDSampling_GBRD_4444:
+		return true;
+	}
+	return false;
+}
+
+VPIDStandard VPIDData::Standard() const
+{
+	return mStandardA;
+}
+
+VPIDSampling VPIDData::Sampling() const
+{
+	return mSamplingA;
+}

+ 43 - 0
plugins/aja/aja-vpid-data.hpp

@@ -0,0 +1,43 @@
+#pragma once
+
+#include <ajantv2/includes/ntv2enums.h>
+#include <ajantv2/includes/ntv2vpid.h>
+
+/*
+ * Wrapper class for handling SMPTE 352M Video Payload ID (VPID) data
+ * Each SDI data stream contains two 32-bit VPID bitfields, representing
+ * characteristics about the video streams on the SDI wire. AJA and other SDI
+ * devices may use VPID to help determine what kind of video data is being
+ * conveyed by the incoming/outgoing streams.
+ */
+class VPIDData {
+public:
+	VPIDData();
+	VPIDData(ULWord vpidA, ULWord vpidB);
+	VPIDData(const VPIDData &other);
+	VPIDData(VPIDData &&other);
+	~VPIDData() = default;
+
+	VPIDData &operator=(const VPIDData &other);
+	VPIDData &operator=(VPIDData &&other);
+	bool operator==(const VPIDData &rhs) const;
+	bool operator!=(const VPIDData &rhs) const;
+
+	void SetA(ULWord vpidA);
+	void SetB(ULWord vpidB);
+	void Parse();
+	bool IsRGB() const;
+
+	VPIDStandard Standard() const;
+	VPIDSampling Sampling() const;
+
+private:
+	ULWord mVpidA;
+	ULWord mVpidB;
+	VPIDStandard mStandardA;
+	VPIDSampling mSamplingA;
+	VPIDStandard mStandardB;
+	VPIDSampling mSamplingB;
+};
+
+using VPIDDataList = std::vector<VPIDData>;

+ 313 - 306
plugins/aja/aja-widget-io.cpp

@@ -1,6 +1,7 @@
 #include "aja-widget-io.hpp"
 
 #include <ajantv2/includes/ntv2utils.h>
+#include <ajantv2/includes/ntv2signalrouter.h>
 
 #include <iostream>
 
@@ -31,312 +32,312 @@ static const char *kOENickname = "oe";
 // Table of firmware widget's input crosspoint/id/channel/name/datastream index
 // clang-format off
 static const WidgetInputSocket kWidgetInputSockets[] = {
-	//NTV2InputCrosspointID        | NTV2WidgetID               | NTV2Channel           | Name | DatastreamIndex
-	{ NTV2_INPUT_CROSSPOINT_INVALID, NTV2_WIDGET_INVALID,         NTV2_CHANNEL_INVALID, "",                    -1},
-	{ NTV2_XptFrameBuffer1Input,     NTV2_WgtFrameBuffer1,        NTV2_CHANNEL1,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer1BInput,    NTV2_WgtFrameBuffer1,        NTV2_CHANNEL1,        kFramebufferNickname,   1},
-	{ NTV2_XptFrameBuffer2Input,     NTV2_WgtFrameBuffer2,        NTV2_CHANNEL2,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer2BInput,    NTV2_WgtFrameBuffer2,        NTV2_CHANNEL2,        kFramebufferNickname,   1},
-	{ NTV2_XptFrameBuffer3Input,     NTV2_WgtFrameBuffer3,        NTV2_CHANNEL3,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer3BInput,    NTV2_WgtFrameBuffer3,        NTV2_CHANNEL3,        kFramebufferNickname,   1},
-	{ NTV2_XptFrameBuffer4Input,     NTV2_WgtFrameBuffer4,        NTV2_CHANNEL4,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer4BInput,    NTV2_WgtFrameBuffer4,        NTV2_CHANNEL4,        kFramebufferNickname,   1},
-	{ NTV2_XptFrameBuffer5Input,     NTV2_WgtFrameBuffer5,        NTV2_CHANNEL5,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer5BInput,    NTV2_WgtFrameBuffer5,        NTV2_CHANNEL5,        kFramebufferNickname,   1},
-	{ NTV2_XptFrameBuffer6Input,     NTV2_WgtFrameBuffer6,        NTV2_CHANNEL6,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer6BInput,    NTV2_WgtFrameBuffer6,        NTV2_CHANNEL6,        kFramebufferNickname,   1},
-	{ NTV2_XptFrameBuffer7Input,     NTV2_WgtFrameBuffer7,        NTV2_CHANNEL7,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer7BInput,    NTV2_WgtFrameBuffer7,        NTV2_CHANNEL7,        kFramebufferNickname,   1},
-	{ NTV2_XptFrameBuffer8Input,     NTV2_WgtFrameBuffer8,        NTV2_CHANNEL8,        kFramebufferNickname,   0},
-	{ NTV2_XptFrameBuffer8BInput,    NTV2_WgtFrameBuffer8,        NTV2_CHANNEL8,        kFramebufferNickname,   1},
-	{ NTV2_XptCSC1VidInput,          NTV2_WgtCSC1,                NTV2_CHANNEL1,        kCSCNickname,           0},
-	{ NTV2_XptCSC1KeyInput,          NTV2_WgtCSC1,                NTV2_CHANNEL1,        kCSCNickname,           1},
-	{ NTV2_XptCSC2VidInput,          NTV2_WgtCSC2,                NTV2_CHANNEL2,        kCSCNickname,           0},
-	{ NTV2_XptCSC2KeyInput,          NTV2_WgtCSC2,                NTV2_CHANNEL2,        kCSCNickname,           1},
-	{ NTV2_XptCSC3VidInput,          NTV2_WgtCSC3,                NTV2_CHANNEL3,        kCSCNickname,           0},
-	{ NTV2_XptCSC3KeyInput,          NTV2_WgtCSC3,                NTV2_CHANNEL3,        kCSCNickname,           1},
-	{ NTV2_XptCSC4VidInput,          NTV2_WgtCSC4,                NTV2_CHANNEL4,        kCSCNickname,           0},
-	{ NTV2_XptCSC4KeyInput,          NTV2_WgtCSC4,                NTV2_CHANNEL4,        kCSCNickname,           1},
-	{ NTV2_XptCSC5VidInput,          NTV2_WgtCSC5,                NTV2_CHANNEL5,        kCSCNickname,           0},
-	{ NTV2_XptCSC5KeyInput,          NTV2_WgtCSC5,                NTV2_CHANNEL5,        kCSCNickname,           1},
-	{ NTV2_XptCSC6VidInput,          NTV2_WgtCSC6,                NTV2_CHANNEL6,        kCSCNickname,           0},
-	{ NTV2_XptCSC6KeyInput,          NTV2_WgtCSC6,                NTV2_CHANNEL6,        kCSCNickname,           1},
-	{ NTV2_XptCSC7VidInput,          NTV2_WgtCSC7,                NTV2_CHANNEL7,        kCSCNickname,           0},
-	{ NTV2_XptCSC7KeyInput,          NTV2_WgtCSC7,                NTV2_CHANNEL7,        kCSCNickname,           1},
-	{ NTV2_XptCSC8VidInput,          NTV2_WgtCSC8,                NTV2_CHANNEL8,        kCSCNickname,           0},
-	{ NTV2_XptCSC8KeyInput,          NTV2_WgtCSC8,                NTV2_CHANNEL8,        kCSCNickname,           1},
-	{ NTV2_XptLUT1Input,             NTV2_WgtLUT1,                NTV2_CHANNEL1,        kLUTNickname,           0},
-	{ NTV2_XptLUT2Input,             NTV2_WgtLUT2,                NTV2_CHANNEL2,        kLUTNickname,           0},
-	{ NTV2_XptLUT3Input,             NTV2_WgtLUT3,                NTV2_CHANNEL3,        kLUTNickname,           0},
-	{ NTV2_XptLUT4Input,             NTV2_WgtLUT4,                NTV2_CHANNEL4,        kLUTNickname,           0},
-	{ NTV2_XptLUT5Input,             NTV2_WgtLUT5,                NTV2_CHANNEL5,        kLUTNickname,           0},
-	{ NTV2_XptLUT6Input,             NTV2_WgtLUT6,                NTV2_CHANNEL6,        kLUTNickname,           0},
-	{ NTV2_XptLUT7Input,             NTV2_WgtLUT7,                NTV2_CHANNEL7,        kLUTNickname,           0},
-	{ NTV2_XptLUT8Input,             NTV2_WgtLUT8,                NTV2_CHANNEL8,        kLUTNickname,           0},
-	{ NTV2_XptMultiLinkOut1Input,    NTV2_WgtMultiLinkOut1,       NTV2_CHANNEL1,        kMultiLinkNickname,     0},
-	{ NTV2_XptMultiLinkOut1InputDS2, NTV2_WgtMultiLinkOut1,       NTV2_CHANNEL1,        kMultiLinkNickname,     0},
-	{ NTV2_XptMultiLinkOut2Input,    NTV2_WgtMultiLinkOut2,       NTV2_CHANNEL1,        kMultiLinkNickname,     0},
-	{ NTV2_XptMultiLinkOut2InputDS2, NTV2_WgtMultiLinkOut2,       NTV2_CHANNEL1,        kMultiLinkNickname,     0},
-	{ NTV2_XptSDIOut1Input,          NTV2_WgtSDIOut1,             NTV2_CHANNEL1,        kSDINickname,           0},
-	{ NTV2_XptSDIOut1InputDS2,       NTV2_Wgt3GSDIOut1,           NTV2_CHANNEL1,        kSDINickname,           1},
-	{ NTV2_XptSDIOut2Input,          NTV2_WgtSDIOut2,             NTV2_CHANNEL2,        kSDINickname,           0},
-	{ NTV2_XptSDIOut2InputDS2,       NTV2_Wgt3GSDIOut2,           NTV2_CHANNEL2,        kSDINickname,           1},
-	{ NTV2_XptSDIOut3Input,          NTV2_WgtSDIOut3,             NTV2_CHANNEL3,        kSDINickname,           0},
-	{ NTV2_XptSDIOut3InputDS2,       NTV2_Wgt3GSDIOut3,           NTV2_CHANNEL3,        kSDINickname,           1},
-	{ NTV2_XptSDIOut4Input,          NTV2_WgtSDIOut4,             NTV2_CHANNEL4,        kSDINickname,           0},
-	{ NTV2_XptSDIOut4InputDS2,       NTV2_Wgt3GSDIOut4,           NTV2_CHANNEL4,        kSDINickname,           1},
-	{ NTV2_XptSDIOut5Input,          NTV2_WgtSDIMonOut1,          NTV2_CHANNEL5,        kSDINickname,           0},
-	{ NTV2_XptSDIOut5InputDS2,       NTV2_WgtSDIMonOut1,          NTV2_CHANNEL5,        kSDINickname,           1},
-	{ NTV2_XptSDIOut6Input,          NTV2_Wgt3GSDIOut6,           NTV2_CHANNEL6,        kSDINickname,           0},
-	{ NTV2_XptSDIOut6InputDS2,       NTV2_Wgt3GSDIOut6,           NTV2_CHANNEL6,        kSDINickname,           1},
-	{ NTV2_XptSDIOut7Input,          NTV2_Wgt3GSDIOut7,           NTV2_CHANNEL7,        kSDINickname,           0},
-	{ NTV2_XptSDIOut7InputDS2,       NTV2_Wgt3GSDIOut7,           NTV2_CHANNEL7,        kSDINickname,           1},
-	{ NTV2_XptSDIOut8Input,          NTV2_Wgt3GSDIOut8,           NTV2_CHANNEL8,        kSDINickname,           0},
-	{ NTV2_XptSDIOut8InputDS2,       NTV2_Wgt3GSDIOut8,           NTV2_CHANNEL8,        kSDINickname,           1},
-	{ NTV2_XptDualLinkIn1Input,      NTV2_WgtDualLinkV2In1,       NTV2_CHANNEL1,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn1DSInput,    NTV2_WgtDualLinkV2In1,       NTV2_CHANNEL1,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkIn2Input,      NTV2_WgtDualLinkV2In2,       NTV2_CHANNEL2,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn2DSInput,    NTV2_WgtDualLinkV2In2,       NTV2_CHANNEL2,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkIn3Input,      NTV2_WgtDualLinkV2In3,       NTV2_CHANNEL3,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn3DSInput,    NTV2_WgtDualLinkV2In3,       NTV2_CHANNEL3,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkIn4Input,      NTV2_WgtDualLinkV2In4,       NTV2_CHANNEL4,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn4DSInput,    NTV2_WgtDualLinkV2In4,       NTV2_CHANNEL4,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkIn5Input,      NTV2_WgtDualLinkV2In5,       NTV2_CHANNEL5,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn5DSInput,    NTV2_WgtDualLinkV2In5,       NTV2_CHANNEL5,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkIn6Input,      NTV2_WgtDualLinkV2In6,       NTV2_CHANNEL6,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn6DSInput,    NTV2_WgtDualLinkV2In6,       NTV2_CHANNEL6,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkIn7Input,      NTV2_WgtDualLinkV2In7,       NTV2_CHANNEL7,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn7DSInput,    NTV2_WgtDualLinkV2In7,       NTV2_CHANNEL7,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkIn8Input,      NTV2_WgtDualLinkV2In8,       NTV2_CHANNEL8,        kDualLinkInNickname,    0},
-	{ NTV2_XptDualLinkIn8DSInput,    NTV2_WgtDualLinkV2In8,       NTV2_CHANNEL8,        kDualLinkInNickname,    1},
-	{ NTV2_XptDualLinkOut1Input,     NTV2_WgtDualLinkV2Out1,      NTV2_CHANNEL1,        kDualLinkOutNickname,   0},
-	{ NTV2_XptDualLinkOut2Input,     NTV2_WgtDualLinkV2Out2,      NTV2_CHANNEL2,        kDualLinkOutNickname,   0},
-	{ NTV2_XptDualLinkOut3Input,     NTV2_WgtDualLinkV2Out3,      NTV2_CHANNEL3,        kDualLinkOutNickname,   0},
-	{ NTV2_XptDualLinkOut4Input,     NTV2_WgtDualLinkV2Out4,      NTV2_CHANNEL4,        kDualLinkOutNickname,   0},
-	{ NTV2_XptDualLinkOut5Input,     NTV2_WgtDualLinkV2Out5,      NTV2_CHANNEL5,        kDualLinkOutNickname,   0},
-	{ NTV2_XptDualLinkOut6Input,     NTV2_WgtDualLinkV2Out6,      NTV2_CHANNEL6,        kDualLinkOutNickname,   0},
-	{ NTV2_XptDualLinkOut7Input,     NTV2_WgtDualLinkV2Out7,      NTV2_CHANNEL7,        kDualLinkOutNickname,   0},
-	{ NTV2_XptDualLinkOut8Input,     NTV2_WgtDualLinkV2Out8,      NTV2_CHANNEL8,        kDualLinkOutNickname,   0},
-	{ NTV2_XptMixer1BGKeyInput,      NTV2_WgtMixer1,              NTV2_CHANNEL1,        kMixerNickname,         3},
-	{ NTV2_XptMixer1BGVidInput,      NTV2_WgtMixer1,              NTV2_CHANNEL1,        kMixerNickname,         2},
-	{ NTV2_XptMixer1FGKeyInput,      NTV2_WgtMixer1,              NTV2_CHANNEL1,        kMixerNickname,         1},
-	{ NTV2_XptMixer1FGVidInput,      NTV2_WgtMixer1,              NTV2_CHANNEL1,        kMixerNickname,         0},
-	{ NTV2_XptMixer2BGKeyInput,      NTV2_WgtMixer2,              NTV2_CHANNEL2,        kMixerNickname,         3},
-	{ NTV2_XptMixer2BGVidInput,      NTV2_WgtMixer2,              NTV2_CHANNEL2,        kMixerNickname,         2},
-	{ NTV2_XptMixer2FGKeyInput,      NTV2_WgtMixer2,              NTV2_CHANNEL2,        kMixerNickname,         1},
-	{ NTV2_XptMixer2FGVidInput,      NTV2_WgtMixer2,              NTV2_CHANNEL2,        kMixerNickname,         0},
-	{ NTV2_XptMixer3BGKeyInput,      NTV2_WgtMixer3,              NTV2_CHANNEL3,        kMixerNickname,         3},
-	{ NTV2_XptMixer3BGVidInput,      NTV2_WgtMixer3,              NTV2_CHANNEL3,        kMixerNickname,         2},
-	{ NTV2_XptMixer3FGKeyInput,      NTV2_WgtMixer3,              NTV2_CHANNEL3,        kMixerNickname,         1},
-	{ NTV2_XptMixer3FGVidInput,      NTV2_WgtMixer3,              NTV2_CHANNEL3,        kMixerNickname,         0},
-	{ NTV2_XptMixer4BGKeyInput,      NTV2_WgtMixer4,              NTV2_CHANNEL4,        kMixerNickname,         3},
-	{ NTV2_XptMixer4BGVidInput,      NTV2_WgtMixer4,              NTV2_CHANNEL4,        kMixerNickname,         2},
-	{ NTV2_XptMixer4FGKeyInput,      NTV2_WgtMixer4,              NTV2_CHANNEL4,        kMixerNickname,         1},
-	{ NTV2_XptMixer4FGVidInput,      NTV2_WgtMixer4,              NTV2_CHANNEL4,        kMixerNickname,         0},
-	{ NTV2_XptHDMIOutInput,          NTV2_WgtHDMIOut1,            NTV2_CHANNEL1,        kHDMINickname,          0},
-	{ NTV2_XptHDMIOutQ2Input,        NTV2_WgtHDMIOut1v2,          NTV2_CHANNEL1,        kHDMINickname,          1},
-	{ NTV2_XptHDMIOutQ3Input,        NTV2_WgtHDMIOut1v2,          NTV2_CHANNEL1,        kHDMINickname,          2},
-	{ NTV2_XptHDMIOutQ4Input,        NTV2_WgtHDMIOut1v2,          NTV2_CHANNEL1,        kHDMINickname,          3},
-	{ NTV2_Xpt4KDCQ1Input,           NTV2_Wgt4KDownConverter,     NTV2_CHANNEL1,        k4KDownConvertNickname, 0},
-	{ NTV2_Xpt4KDCQ2Input,           NTV2_Wgt4KDownConverter,     NTV2_CHANNEL2,        k4KDownConvertNickname, 0},
-	{ NTV2_Xpt4KDCQ3Input,           NTV2_Wgt4KDownConverter,     NTV2_CHANNEL3,        k4KDownConvertNickname, 0},
-	{ NTV2_Xpt4KDCQ4Input,           NTV2_Wgt4KDownConverter,     NTV2_CHANNEL4,        k4KDownConvertNickname, 0},
-	{ NTV2_Xpt425Mux1AInput,         NTV2_Wgt425Mux1,             NTV2_CHANNEL1,        kTSIMuxNickname,        0},
-	{ NTV2_Xpt425Mux1BInput,         NTV2_Wgt425Mux1,             NTV2_CHANNEL1,        kTSIMuxNickname,        1},
-	{ NTV2_Xpt425Mux2AInput,         NTV2_Wgt425Mux2,             NTV2_CHANNEL2,        kTSIMuxNickname,        0},
-	{ NTV2_Xpt425Mux2BInput,         NTV2_Wgt425Mux2,             NTV2_CHANNEL2,        kTSIMuxNickname,        1},
-	{ NTV2_Xpt425Mux3AInput,         NTV2_Wgt425Mux3,             NTV2_CHANNEL3,        kTSIMuxNickname,        0},
-	{ NTV2_Xpt425Mux3BInput,         NTV2_Wgt425Mux3,             NTV2_CHANNEL3,        kTSIMuxNickname,        1},
-	{ NTV2_Xpt425Mux4AInput,         NTV2_Wgt425Mux4,             NTV2_CHANNEL4,        kTSIMuxNickname,        0},
-	{ NTV2_Xpt425Mux4BInput,         NTV2_Wgt425Mux4,             NTV2_CHANNEL4,        kTSIMuxNickname,        1},
-	{ NTV2_XptAnalogOutInput,        NTV2_WgtAnalogOut1,          NTV2_CHANNEL1,        kAnalogNickname,        0},
-	{ NTV2_Xpt3DLUT1Input,           NTV2_Wgt3DLUT1,              NTV2_CHANNEL1,        kLUT3DNickname,         0},
-	{ NTV2_XptAnalogOutCompositeOut, NTV2_WgtAnalogCompositeOut1, NTV2_CHANNEL1,        kCompositeNickname,     0},
-	{ NTV2_XptStereoLeftInput,       NTV2_WgtStereoCompressor,    NTV2_CHANNEL1,        kStereoCompNickname,    0},
-	{ NTV2_XptStereoRightInput,      NTV2_WgtStereoCompressor,    NTV2_CHANNEL1,        kStereoCompNickname,    0},
-	{ NTV2_XptWaterMarker1Input,     NTV2_WgtWaterMarker1,        NTV2_CHANNEL1,        kWatermarkNickname,     0},
-	{ NTV2_XptWaterMarker2Input,     NTV2_WgtWaterMarker2,        NTV2_CHANNEL2,        kWatermarkNickname,     0},
-	{ NTV2_XptConversionMod2Input,   NTV2_WgtUpDownConverter2,    NTV2_CHANNEL2,        kUpDownConvertNickname, 0},
-	{ NTV2_XptCompressionModInput,   NTV2_WgtCompression1,        NTV2_CHANNEL1,        kCompressionNickname,   0},
-	{ NTV2_XptConversionModInput,    NTV2_WgtUpDownConverter1,    NTV2_CHANNEL1,        kUpDownConvertNickname, 0},
-	{ NTV2_XptFrameSync2Input,       NTV2_WgtFrameSync2,          NTV2_CHANNEL2,        kFrameSyncNickname,     0},
+	//NTV2InputCrosspointID        | NTV2WidgetID                | Name | DatastreamIndex
+	{ NTV2_INPUT_CROSSPOINT_INVALID, NTV2_WIDGET_INVALID,          "",                    -1},
+	{ NTV2_XptFrameBuffer1Input,     NTV2_WgtFrameBuffer1,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer1BInput,    NTV2_WgtFrameBuffer1,                kFramebufferNickname,   1},
+	{ NTV2_XptFrameBuffer2Input,     NTV2_WgtFrameBuffer2,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer2BInput,    NTV2_WgtFrameBuffer2,                kFramebufferNickname,   1},
+	{ NTV2_XptFrameBuffer3Input,     NTV2_WgtFrameBuffer3,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer3BInput,    NTV2_WgtFrameBuffer3,                kFramebufferNickname,   1},
+	{ NTV2_XptFrameBuffer4Input,     NTV2_WgtFrameBuffer4,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer4BInput,    NTV2_WgtFrameBuffer4,                kFramebufferNickname,   1},
+	{ NTV2_XptFrameBuffer5Input,     NTV2_WgtFrameBuffer5,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer5BInput,    NTV2_WgtFrameBuffer5,                kFramebufferNickname,   1},
+	{ NTV2_XptFrameBuffer6Input,     NTV2_WgtFrameBuffer6,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer6BInput,    NTV2_WgtFrameBuffer6,                kFramebufferNickname,   1},
+	{ NTV2_XptFrameBuffer7Input,     NTV2_WgtFrameBuffer7,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer7BInput,    NTV2_WgtFrameBuffer7,                kFramebufferNickname,   1},
+	{ NTV2_XptFrameBuffer8Input,     NTV2_WgtFrameBuffer8,                kFramebufferNickname,   0},
+	{ NTV2_XptFrameBuffer8BInput,    NTV2_WgtFrameBuffer8,                kFramebufferNickname,   1},
+	{ NTV2_XptCSC1VidInput,          NTV2_WgtCSC1,                        kCSCNickname,           0},
+	{ NTV2_XptCSC1KeyInput,          NTV2_WgtCSC1,                        kCSCNickname,           1},
+	{ NTV2_XptCSC2VidInput,          NTV2_WgtCSC2,                        kCSCNickname,           0},
+	{ NTV2_XptCSC2KeyInput,          NTV2_WgtCSC2,                        kCSCNickname,           1},
+	{ NTV2_XptCSC3VidInput,          NTV2_WgtCSC3,                        kCSCNickname,           0},
+	{ NTV2_XptCSC3KeyInput,          NTV2_WgtCSC3,                        kCSCNickname,           1},
+	{ NTV2_XptCSC4VidInput,          NTV2_WgtCSC4,                        kCSCNickname,           0},
+	{ NTV2_XptCSC4KeyInput,          NTV2_WgtCSC4,                        kCSCNickname,           1},
+	{ NTV2_XptCSC5VidInput,          NTV2_WgtCSC5,                        kCSCNickname,           0},
+	{ NTV2_XptCSC5KeyInput,          NTV2_WgtCSC5,                        kCSCNickname,           1},
+	{ NTV2_XptCSC6VidInput,          NTV2_WgtCSC6,                        kCSCNickname,           0},
+	{ NTV2_XptCSC6KeyInput,          NTV2_WgtCSC6,                        kCSCNickname,           1},
+	{ NTV2_XptCSC7VidInput,          NTV2_WgtCSC7,                        kCSCNickname,           0},
+	{ NTV2_XptCSC7KeyInput,          NTV2_WgtCSC7,                        kCSCNickname,           1},
+	{ NTV2_XptCSC8VidInput,          NTV2_WgtCSC8,                        kCSCNickname,           0},
+	{ NTV2_XptCSC8KeyInput,          NTV2_WgtCSC8,                        kCSCNickname,           1},
+	{ NTV2_XptLUT1Input,             NTV2_WgtLUT1,                        kLUTNickname,           0},
+	{ NTV2_XptLUT2Input,             NTV2_WgtLUT2,                        kLUTNickname,           0},
+	{ NTV2_XptLUT3Input,             NTV2_WgtLUT3,                        kLUTNickname,           0},
+	{ NTV2_XptLUT4Input,             NTV2_WgtLUT4,                        kLUTNickname,           0},
+	{ NTV2_XptLUT5Input,             NTV2_WgtLUT5,                        kLUTNickname,           0},
+	{ NTV2_XptLUT6Input,             NTV2_WgtLUT6,                        kLUTNickname,           0},
+	{ NTV2_XptLUT7Input,             NTV2_WgtLUT7,                        kLUTNickname,           0},
+	{ NTV2_XptLUT8Input,             NTV2_WgtLUT8,                        kLUTNickname,           0},
+	{ NTV2_XptMultiLinkOut1Input,    NTV2_WgtMultiLinkOut1,               kMultiLinkNickname,     0},
+	{ NTV2_XptMultiLinkOut1InputDS2, NTV2_WgtMultiLinkOut1,               kMultiLinkNickname,     0},
+	{ NTV2_XptMultiLinkOut2Input,    NTV2_WgtMultiLinkOut2,               kMultiLinkNickname,     0},
+	{ NTV2_XptMultiLinkOut2InputDS2, NTV2_WgtMultiLinkOut2,               kMultiLinkNickname,     0},
+	{ NTV2_XptSDIOut1Input,          NTV2_WgtSDIOut1,                     kSDINickname,           0},
+	{ NTV2_XptSDIOut1InputDS2,       NTV2_Wgt3GSDIOut1,                   kSDINickname,           1},
+	{ NTV2_XptSDIOut2Input,          NTV2_WgtSDIOut2,                     kSDINickname,           0},
+	{ NTV2_XptSDIOut2InputDS2,       NTV2_Wgt3GSDIOut2,                   kSDINickname,           1},
+	{ NTV2_XptSDIOut3Input,          NTV2_WgtSDIOut3,                     kSDINickname,           0},
+	{ NTV2_XptSDIOut3InputDS2,       NTV2_Wgt3GSDIOut3,                   kSDINickname,           1},
+	{ NTV2_XptSDIOut4Input,          NTV2_WgtSDIOut4,                     kSDINickname,           0},
+	{ NTV2_XptSDIOut4InputDS2,       NTV2_Wgt3GSDIOut4,                   kSDINickname,           1},
+	{ NTV2_XptSDIOut5Input,          NTV2_WgtSDIMonOut1,                  kSDINickname,           0},
+	{ NTV2_XptSDIOut5InputDS2,       NTV2_WgtSDIMonOut1,                  kSDINickname,           1},
+	{ NTV2_XptSDIOut6Input,          NTV2_Wgt3GSDIOut6,                   kSDINickname,           0},
+	{ NTV2_XptSDIOut6InputDS2,       NTV2_Wgt3GSDIOut6,                   kSDINickname,           1},
+	{ NTV2_XptSDIOut7Input,          NTV2_Wgt3GSDIOut7,                   kSDINickname,           0},
+	{ NTV2_XptSDIOut7InputDS2,       NTV2_Wgt3GSDIOut7,                   kSDINickname,           1},
+	{ NTV2_XptSDIOut8Input,          NTV2_Wgt3GSDIOut8,                   kSDINickname,           0},
+	{ NTV2_XptSDIOut8InputDS2,       NTV2_Wgt3GSDIOut8,                   kSDINickname,           1},
+	{ NTV2_XptDualLinkIn1Input,      NTV2_WgtDualLinkV2In1,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn1DSInput,    NTV2_WgtDualLinkV2In1,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkIn2Input,      NTV2_WgtDualLinkV2In2,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn2DSInput,    NTV2_WgtDualLinkV2In2,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkIn3Input,      NTV2_WgtDualLinkV2In3,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn3DSInput,    NTV2_WgtDualLinkV2In3,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkIn4Input,      NTV2_WgtDualLinkV2In4,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn4DSInput,    NTV2_WgtDualLinkV2In4,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkIn5Input,      NTV2_WgtDualLinkV2In5,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn5DSInput,    NTV2_WgtDualLinkV2In5,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkIn6Input,      NTV2_WgtDualLinkV2In6,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn6DSInput,    NTV2_WgtDualLinkV2In6,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkIn7Input,      NTV2_WgtDualLinkV2In7,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn7DSInput,    NTV2_WgtDualLinkV2In7,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkIn8Input,      NTV2_WgtDualLinkV2In8,               kDualLinkInNickname,    0},
+	{ NTV2_XptDualLinkIn8DSInput,    NTV2_WgtDualLinkV2In8,               kDualLinkInNickname,    1},
+	{ NTV2_XptDualLinkOut1Input,     NTV2_WgtDualLinkV2Out1,              kDualLinkOutNickname,   0},
+	{ NTV2_XptDualLinkOut2Input,     NTV2_WgtDualLinkV2Out2,              kDualLinkOutNickname,   0},
+	{ NTV2_XptDualLinkOut3Input,     NTV2_WgtDualLinkV2Out3,              kDualLinkOutNickname,   0},
+	{ NTV2_XptDualLinkOut4Input,     NTV2_WgtDualLinkV2Out4,              kDualLinkOutNickname,   0},
+	{ NTV2_XptDualLinkOut5Input,     NTV2_WgtDualLinkV2Out5,              kDualLinkOutNickname,   0},
+	{ NTV2_XptDualLinkOut6Input,     NTV2_WgtDualLinkV2Out6,              kDualLinkOutNickname,   0},
+	{ NTV2_XptDualLinkOut7Input,     NTV2_WgtDualLinkV2Out7,              kDualLinkOutNickname,   0},
+	{ NTV2_XptDualLinkOut8Input,     NTV2_WgtDualLinkV2Out8,              kDualLinkOutNickname,   0},
+	{ NTV2_XptMixer1BGKeyInput,      NTV2_WgtMixer1,                      kMixerNickname,         3},
+	{ NTV2_XptMixer1BGVidInput,      NTV2_WgtMixer1,                      kMixerNickname,         2},
+	{ NTV2_XptMixer1FGKeyInput,      NTV2_WgtMixer1,                      kMixerNickname,         1},
+	{ NTV2_XptMixer1FGVidInput,      NTV2_WgtMixer1,                      kMixerNickname,         0},
+	{ NTV2_XptMixer2BGKeyInput,      NTV2_WgtMixer2,                      kMixerNickname,         3},
+	{ NTV2_XptMixer2BGVidInput,      NTV2_WgtMixer2,                      kMixerNickname,         2},
+	{ NTV2_XptMixer2FGKeyInput,      NTV2_WgtMixer2,                      kMixerNickname,         1},
+	{ NTV2_XptMixer2FGVidInput,      NTV2_WgtMixer2,                      kMixerNickname,         0},
+	{ NTV2_XptMixer3BGKeyInput,      NTV2_WgtMixer3,                      kMixerNickname,         3},
+	{ NTV2_XptMixer3BGVidInput,      NTV2_WgtMixer3,                      kMixerNickname,         2},
+	{ NTV2_XptMixer3FGKeyInput,      NTV2_WgtMixer3,                      kMixerNickname,         1},
+	{ NTV2_XptMixer3FGVidInput,      NTV2_WgtMixer3,                      kMixerNickname,         0},
+	{ NTV2_XptMixer4BGKeyInput,      NTV2_WgtMixer4,                      kMixerNickname,         3},
+	{ NTV2_XptMixer4BGVidInput,      NTV2_WgtMixer4,                      kMixerNickname,         2},
+	{ NTV2_XptMixer4FGKeyInput,      NTV2_WgtMixer4,                      kMixerNickname,         1},
+	{ NTV2_XptMixer4FGVidInput,      NTV2_WgtMixer4,                      kMixerNickname,         0},
+	{ NTV2_XptHDMIOutInput,          NTV2_WgtHDMIOut1,                    kHDMINickname,          0},
+	{ NTV2_XptHDMIOutQ2Input,        NTV2_WgtHDMIOut1v2,                  kHDMINickname,          1},
+	{ NTV2_XptHDMIOutQ3Input,        NTV2_WgtHDMIOut1v2,                  kHDMINickname,          2},
+	{ NTV2_XptHDMIOutQ4Input,        NTV2_WgtHDMIOut1v2,                  kHDMINickname,          3},
+	{ NTV2_Xpt4KDCQ1Input,           NTV2_Wgt4KDownConverter,             k4KDownConvertNickname, 0},
+	{ NTV2_Xpt4KDCQ2Input,           NTV2_Wgt4KDownConverter,             k4KDownConvertNickname, 0},
+	{ NTV2_Xpt4KDCQ3Input,           NTV2_Wgt4KDownConverter,             k4KDownConvertNickname, 0},
+	{ NTV2_Xpt4KDCQ4Input,           NTV2_Wgt4KDownConverter,             k4KDownConvertNickname, 0},
+	{ NTV2_Xpt425Mux1AInput,         NTV2_Wgt425Mux1,                     kTSIMuxNickname,        0},
+	{ NTV2_Xpt425Mux1BInput,         NTV2_Wgt425Mux1,                     kTSIMuxNickname,        1},
+	{ NTV2_Xpt425Mux2AInput,         NTV2_Wgt425Mux2,                     kTSIMuxNickname,        0},
+	{ NTV2_Xpt425Mux2BInput,         NTV2_Wgt425Mux2,                     kTSIMuxNickname,        1},
+	{ NTV2_Xpt425Mux3AInput,         NTV2_Wgt425Mux3,                     kTSIMuxNickname,        0},
+	{ NTV2_Xpt425Mux3BInput,         NTV2_Wgt425Mux3,                     kTSIMuxNickname,        1},
+	{ NTV2_Xpt425Mux4AInput,         NTV2_Wgt425Mux4,                     kTSIMuxNickname,        0},
+	{ NTV2_Xpt425Mux4BInput,         NTV2_Wgt425Mux4,                     kTSIMuxNickname,        1},
+	{ NTV2_XptAnalogOutInput,        NTV2_WgtAnalogOut1,                  kAnalogNickname,        0},
+	{ NTV2_Xpt3DLUT1Input,           NTV2_Wgt3DLUT1,                      kLUT3DNickname,         0},
+	{ NTV2_XptAnalogOutCompositeOut, NTV2_WgtAnalogCompositeOut1,         kCompositeNickname,     0},
+	{ NTV2_XptStereoLeftInput,       NTV2_WgtStereoCompressor,            kStereoCompNickname,    0},
+	{ NTV2_XptStereoRightInput,      NTV2_WgtStereoCompressor,            kStereoCompNickname,    0},
+	{ NTV2_XptWaterMarker1Input,     NTV2_WgtWaterMarker1,                kWatermarkNickname,     0},
+	{ NTV2_XptWaterMarker2Input,     NTV2_WgtWaterMarker2,                kWatermarkNickname,     0},
+	{ NTV2_XptConversionMod2Input,   NTV2_WgtUpDownConverter2,            kUpDownConvertNickname, 0},
+	{ NTV2_XptCompressionModInput,   NTV2_WgtCompression1,                kCompressionNickname,   0},
+	{ NTV2_XptConversionModInput,    NTV2_WgtUpDownConverter1,            kUpDownConvertNickname, 0},
+	{ NTV2_XptFrameSync2Input,       NTV2_WgtFrameSync2,                  kFrameSyncNickname,     0},
 };
 
 // Table of firmware widget's output crosspoint/id/channel/name/datastream index
 static WidgetOutputSocket kWidgetOutputSockets[] = {
-	{ NTV2_OUTPUT_CROSSPOINT_INVALID, NTV2_WIDGET_INVALID, NTV2_CHANNEL_INVALID, "", -1},
-	{ NTV2_XptBlack,                 NTV2_WgtUndefined,           NTV2_CHANNEL1,        kBlackNickname,                0},
-	{ NTV2_XptSDIIn1,                NTV2_WgtSDIIn1,              NTV2_CHANNEL1,        kSDINickname,                  0},
-	{ NTV2_XptSDIIn2,                NTV2_WgtSDIIn2,              NTV2_CHANNEL2,        kSDINickname,                  0},
-	{ NTV2_XptLUT1YUV,               NTV2_WgtLUT1,                NTV2_CHANNEL1,        kSDINickname,                  0},
-	{ NTV2_XptCSC1VidYUV,            NTV2_WgtCSC1,                NTV2_CHANNEL1,        kCSCNickname,                  0},
-	{ NTV2_XptConversionModule,      NTV2_WgtUpDownConverter1,    NTV2_CHANNEL1,        kUpDownConvertNickname,        0},
-	{ NTV2_XptCompressionModule,     NTV2_WgtCompression1,        NTV2_CHANNEL1,        kCompressionNickname,          0},
-	{ NTV2_XptFrameBuffer1YUV,       NTV2_WgtFrameBuffer1,        NTV2_CHANNEL1,        kFramebufferNickname,          0},
-	{ NTV2_XptFrameSync1YUV,         NTV2_WgtFrameSync1,          NTV2_CHANNEL1,        kFrameSyncNickname,            0},
-	{ NTV2_XptFrameSync2YUV,         NTV2_WgtFrameSync2,          NTV2_CHANNEL2,        kFrameSyncNickname,            0},
-	{ NTV2_XptDuallinkOut1,          NTV2_WgtDualLinkV2Out1,      NTV2_CHANNEL1,        kDualLinkOutNickname,          0},
-	{ NTV2_XptCSC1KeyYUV,            NTV2_WgtCSC1,                NTV2_CHANNEL1,        kCSCNickname,                  2},
-	{ NTV2_XptFrameBuffer2YUV,       NTV2_WgtFrameBuffer2,        NTV2_CHANNEL2,        kFramebufferNickname,          0},
-	{ NTV2_XptCSC2VidYUV,            NTV2_WgtCSC2,                NTV2_CHANNEL2,        kCSCNickname,                  0},
-	{ NTV2_XptCSC2KeyYUV,            NTV2_WgtCSC2,                NTV2_CHANNEL2,        kCSCNickname,                  2},
-	{ NTV2_XptMixer1VidYUV,          NTV2_WgtMixer1,              NTV2_CHANNEL1,        kMixerNickname,                0},
-	{ NTV2_XptMixer1KeyYUV,          NTV2_WgtMixer1,              NTV2_CHANNEL1,        kMixerNickname,                1},
-	{ NTV2_XptMultiLinkOut1DS1,      NTV2_WgtMultiLinkOut1,       NTV2_CHANNEL1,        kMultiLinkNickname,            0},
-	{ NTV2_XptMultiLinkOut1DS2,      NTV2_WgtMultiLinkOut1,       NTV2_CHANNEL1,        kMultiLinkNickname,            1},
-	{ NTV2_XptAnalogIn,              NTV2_WgtAnalogIn1,           NTV2_CHANNEL1,        kAnalogNickname,               0},
-	{ NTV2_XptHDMIIn1,               NTV2_WgtHDMIIn1,             NTV2_CHANNEL1,        kHDMINickname,                 0},
-	{ NTV2_XptMultiLinkOut1DS3,      NTV2_WgtMultiLinkOut1,       NTV2_CHANNEL1,        kMultiLinkNickname,            2},
-	{ NTV2_XptMultiLinkOut1DS4,      NTV2_WgtMultiLinkOut1,       NTV2_CHANNEL1,        kMultiLinkNickname,            3},
-	{ NTV2_XptMultiLinkOut2DS1,      NTV2_WgtMultiLinkOut2,       NTV2_CHANNEL2,        kMultiLinkNickname,            0},
-	{ NTV2_XptMultiLinkOut2DS2,      NTV2_WgtMultiLinkOut2,       NTV2_CHANNEL2,        kMultiLinkNickname,            1},
-	{ NTV2_XptDuallinkOut2,          NTV2_WgtDualLinkV2Out2,      NTV2_CHANNEL2,        kDualLinkOutNickname,          0},
-	{ NTV2_XptTestPatternYUV,        NTV2_WgtTestPattern1,        NTV2_CHANNEL1,        kTestPatternNickname,          0},
-	{ NTV2_XptSDIIn1DS2,             NTV2_Wgt3GSDIIn1,            NTV2_CHANNEL1,        kSDINickname,                  1},
-	{ NTV2_XptSDIIn2DS2,             NTV2_Wgt3GSDIIn2,            NTV2_CHANNEL2,        kSDINickname,                  1},
-	{ NTV2_XptMixer2VidYUV,          NTV2_WgtMixer2,              NTV2_CHANNEL2,        kMixerNickname,                0},
-	{ NTV2_XptMixer2KeyYUV,          NTV2_WgtMixer2,              NTV2_CHANNEL2,        kMixerNickname,                1},
-	{ NTV2_XptStereoCompressorOut,   NTV2_WgtStereoCompressor,    NTV2_CHANNEL1,        kStereoCompNickname,           0},
-	{ NTV2_XptFrameBuffer3YUV,       NTV2_WgtFrameBuffer3,        NTV2_CHANNEL3,        kFramebufferNickname,          0},
-	{ NTV2_XptFrameBuffer4YUV,       NTV2_WgtFrameBuffer4,        NTV2_CHANNEL4,        kFramebufferNickname,          0},
-	{ NTV2_XptDuallinkOut1DS2,       NTV2_WgtDualLinkV2Out1,      NTV2_CHANNEL1,        kDualLinkOutNickname,          1},
-	{ NTV2_XptDuallinkOut2DS2,       NTV2_WgtDualLinkV2Out2,      NTV2_CHANNEL2,        kDualLinkOutNickname,          1},
-	{ NTV2_XptCSC5VidYUV,            NTV2_WgtCSC5,                NTV2_CHANNEL5,        kCSCNickname,                  0},
-	{ NTV2_XptCSC5KeyYUV,            NTV2_WgtCSC5,                NTV2_CHANNEL5,        kCSCNickname,                  1},
-	{ NTV2_XptMultiLinkOut2DS3,      NTV2_WgtMultiLinkOut2,       NTV2_CHANNEL2,        kMultiLinkNickname,            2},
-	{ NTV2_XptMultiLinkOut2DS4,      NTV2_WgtMultiLinkOut2,       NTV2_CHANNEL2,        kMultiLinkNickname,            3},
-	{ NTV2_XptSDIIn3,                NTV2_Wgt3GSDIIn3,            NTV2_CHANNEL3,        kSDINickname,                  0},
-	{ NTV2_XptSDIIn4,                NTV2_Wgt3GSDIIn4,            NTV2_CHANNEL4,        kSDINickname,                  0},
-	{ NTV2_XptSDIIn3DS2,             NTV2_Wgt3GSDIIn3,            NTV2_CHANNEL3,        kSDINickname,                  1},
-	{ NTV2_XptSDIIn4DS2,             NTV2_Wgt3GSDIIn4,            NTV2_CHANNEL4,        kSDINickname,                  1},
-	{ NTV2_XptDuallinkOut3,          NTV2_WgtDualLinkV2Out3,      NTV2_CHANNEL3,        kDualLinkOutNickname,          0},
-	{ NTV2_XptDuallinkOut3DS2,       NTV2_WgtDualLinkV2Out3,      NTV2_CHANNEL3,        kDualLinkOutNickname,          1},
-	{ NTV2_XptDuallinkOut4,          NTV2_WgtDualLinkV2Out4,      NTV2_CHANNEL4,        kDualLinkOutNickname,          0},
-	{ NTV2_XptDuallinkOut4DS2,       NTV2_WgtDualLinkV2Out4,      NTV2_CHANNEL4,        kDualLinkOutNickname,          1},
-	{ NTV2_XptCSC3VidYUV,            NTV2_WgtCSC3,                NTV2_CHANNEL3,        kCSCNickname,                  0},
-	{ NTV2_XptCSC3KeyYUV,            NTV2_WgtCSC3,                NTV2_CHANNEL3,        kCSCNickname,                  2},
-	{ NTV2_XptCSC4VidYUV,            NTV2_WgtCSC4,                NTV2_CHANNEL4,        kCSCNickname,                  0},
-	{ NTV2_XptCSC4KeyYUV,            NTV2_WgtCSC4,                NTV2_CHANNEL4,        kCSCNickname,                  2},
-	{ NTV2_XptDuallinkOut5,          NTV2_WgtDualLinkV2Out5,      NTV2_CHANNEL5,        kDualLinkOutNickname,          0},
-	{ NTV2_XptDuallinkOut5DS2,       NTV2_WgtDualLinkV2Out5,      NTV2_CHANNEL5,        kDualLinkOutNickname,          1},
-	{ NTV2_Xpt3DLUT1YUV,             NTV2_Wgt3DLUT1,              NTV2_CHANNEL1,        kLUT3DNickname,                0},
-	{ NTV2_XptHDMIIn1Q2,             NTV2_WgtHDMIIn1v3,           NTV2_CHANNEL1,        kHDMINickname,                 1},
-	{ NTV2_XptHDMIIn1Q3,             NTV2_WgtHDMIIn1v3,           NTV2_CHANNEL1,        kHDMINickname,                 2},
-	{ NTV2_XptHDMIIn1Q4,             NTV2_WgtHDMIIn1v3,           NTV2_CHANNEL1,        kHDMINickname,                 3},
-	{ NTV2_Xpt4KDownConverterOut,    NTV2_Wgt4KDownConverter,     NTV2_CHANNEL1,        k4KDownConvertNickname,        0},
-	{ NTV2_XptSDIIn5,                NTV2_Wgt3GSDIIn5,            NTV2_CHANNEL5,        kSDINickname,                  0},
-	{ NTV2_XptSDIIn6,                NTV2_Wgt3GSDIIn6,            NTV2_CHANNEL6,        kSDINickname,                  0},
-	{ NTV2_XptSDIIn5DS2,             NTV2_Wgt3GSDIIn5,            NTV2_CHANNEL5,        kSDINickname,                  1},
-	{ NTV2_XptSDIIn6DS2,             NTV2_Wgt3GSDIIn6,            NTV2_CHANNEL6,        kSDINickname,                  1},
-	{ NTV2_XptSDIIn7,                NTV2_Wgt3GSDIIn7,            NTV2_CHANNEL7,        kSDINickname,                  0},
-	{ NTV2_XptSDIIn8,                NTV2_Wgt3GSDIIn8,            NTV2_CHANNEL8,        kSDINickname,                  0},
-	{ NTV2_XptSDIIn7DS2,             NTV2_Wgt3GSDIIn7,            NTV2_CHANNEL7,        kSDINickname,                  1},
-	{ NTV2_XptSDIIn8DS2,             NTV2_Wgt3GSDIIn8,            NTV2_CHANNEL8,        kSDINickname,                  1},
-	{ NTV2_XptFrameBuffer5YUV,       NTV2_WgtFrameBuffer5,        NTV2_CHANNEL5,        kFramebufferNickname,          0},
-	{ NTV2_XptFrameBuffer6YUV,       NTV2_WgtFrameBuffer6,        NTV2_CHANNEL6,        kFramebufferNickname,          0},
-	{ NTV2_XptFrameBuffer7YUV,       NTV2_WgtFrameBuffer7,        NTV2_CHANNEL7,        kFramebufferNickname,          0},
-	{ NTV2_XptFrameBuffer8YUV,       NTV2_WgtFrameBuffer8,        NTV2_CHANNEL8,        kFramebufferNickname,          0},
-	{ NTV2_XptMixer3VidYUV,          NTV2_WgtMixer3,              NTV2_CHANNEL3,        kMixerNickname,                0},
-	{ NTV2_XptMixer3KeyYUV,          NTV2_WgtMixer3,              NTV2_CHANNEL3,        kMixerNickname,                1},
-	{ NTV2_XptMixer4VidYUV,          NTV2_WgtMixer4,              NTV2_CHANNEL4,        kMixerNickname,                0},
-	{ NTV2_XptMixer4KeyYUV,          NTV2_WgtMixer4,              NTV2_CHANNEL4,        kMixerNickname,                1},
-	{ NTV2_XptCSC6VidYUV,            NTV2_WgtCSC6,                NTV2_CHANNEL6,        kCSCNickname,                  0},
-	{ NTV2_XptCSC6KeyYUV,            NTV2_WgtCSC6,                NTV2_CHANNEL6,        kCSCNickname,                  1},
-	{ NTV2_XptCSC7VidYUV,            NTV2_WgtCSC7,                NTV2_CHANNEL7,        kCSCNickname,                  0},
-	{ NTV2_XptCSC7KeyYUV,            NTV2_WgtCSC7,                NTV2_CHANNEL7,        kCSCNickname,                  1},
-	{ NTV2_XptCSC8VidYUV,            NTV2_WgtCSC8,                NTV2_CHANNEL8,        kCSCNickname,                  0},
-	{ NTV2_XptCSC8KeyYUV,            NTV2_WgtCSC8,                NTV2_CHANNEL8,        kCSCNickname,                  1},
-	{ NTV2_XptDuallinkOut6,          NTV2_WgtDualLinkV2Out6,      NTV2_CHANNEL6,        kDualLinkOutNickname,          0},
-	{ NTV2_XptDuallinkOut6DS2,       NTV2_WgtDualLinkV2Out6,      NTV2_CHANNEL6,        kDualLinkOutNickname,          1},
-	{ NTV2_XptDuallinkOut7,          NTV2_WgtDualLinkV2Out7,      NTV2_CHANNEL7,        kDualLinkOutNickname,          0},
-	{ NTV2_XptDuallinkOut7DS2,       NTV2_WgtDualLinkV2Out7,      NTV2_CHANNEL7,        kDualLinkOutNickname,          1},
-	{ NTV2_XptDuallinkOut8,          NTV2_WgtDualLinkV2Out8,      NTV2_CHANNEL8,        kDualLinkOutNickname,          0},
-	{ NTV2_XptDuallinkOut8DS2,       NTV2_WgtDualLinkV2Out8,      NTV2_CHANNEL8,        kDualLinkOutNickname,          1},
-	{ NTV2_Xpt425Mux1AYUV,           NTV2_Wgt425Mux1,             NTV2_CHANNEL1,        kTSIMuxNickname,               0},
-	{ NTV2_Xpt425Mux1BYUV,           NTV2_Wgt425Mux1,             NTV2_CHANNEL1,        kTSIMuxNickname,               1},
-	{ NTV2_Xpt425Mux2AYUV,           NTV2_Wgt425Mux2,             NTV2_CHANNEL2,        kTSIMuxNickname,               0},
-	{ NTV2_Xpt425Mux2BYUV,           NTV2_Wgt425Mux2,             NTV2_CHANNEL2,        kTSIMuxNickname,               1},
-	{ NTV2_Xpt425Mux3AYUV,           NTV2_Wgt425Mux3,             NTV2_CHANNEL3,        kTSIMuxNickname,               0},
-	{ NTV2_Xpt425Mux3BYUV,           NTV2_Wgt425Mux3,             NTV2_CHANNEL3,        kTSIMuxNickname,               1},
-	{ NTV2_Xpt425Mux4AYUV,           NTV2_Wgt425Mux4,             NTV2_CHANNEL4,        kTSIMuxNickname,               0},
-	{ NTV2_Xpt425Mux4BYUV,           NTV2_Wgt425Mux4,             NTV2_CHANNEL4,        kTSIMuxNickname,               1},
-	{ NTV2_XptFrameBuffer1_DS2YUV,   NTV2_WgtFrameBuffer1,        NTV2_CHANNEL1,        kFramebufferNickname,          1},
-	{ NTV2_XptFrameBuffer2_DS2YUV,   NTV2_WgtFrameBuffer2,        NTV2_CHANNEL2,        kFramebufferNickname,          1},
-	{ NTV2_XptFrameBuffer3_DS2YUV,   NTV2_WgtFrameBuffer3,        NTV2_CHANNEL3,        kFramebufferNickname,          1},
-	{ NTV2_XptFrameBuffer4_DS2YUV,   NTV2_WgtFrameBuffer4,        NTV2_CHANNEL4,        kFramebufferNickname,          1},
-	{ NTV2_XptFrameBuffer5_DS2YUV,   NTV2_WgtFrameBuffer5,        NTV2_CHANNEL5,        kFramebufferNickname,          1},
-	{ NTV2_XptFrameBuffer6_DS2YUV,   NTV2_WgtFrameBuffer6,        NTV2_CHANNEL6,        kFramebufferNickname,          1},
-	{ NTV2_XptFrameBuffer7_DS2YUV,   NTV2_WgtFrameBuffer7,        NTV2_CHANNEL7,        kFramebufferNickname,          1},
-	{ NTV2_XptFrameBuffer8_DS2YUV,   NTV2_WgtFrameBuffer8,        NTV2_CHANNEL8,        kFramebufferNickname,          1},
-	{ NTV2_XptHDMIIn2,               NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 0},
-	{ NTV2_XptHDMIIn2Q2,             NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 1},
-	{ NTV2_XptHDMIIn2Q3,             NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 2},
-	{ NTV2_XptHDMIIn2Q4,             NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 3},
-	{ NTV2_XptHDMIIn3,               NTV2_WgtHDMIIn3v4,           NTV2_CHANNEL3,        kHDMINickname,                 0},
-	{ NTV2_XptHDMIIn4,               NTV2_WgtHDMIIn4v4,           NTV2_CHANNEL4,        kHDMINickname,                 0},
-	{ NTV2_XptDuallinkIn1,           NTV2_WgtDualLinkV2In1,       NTV2_CHANNEL1,        kDualLinkInNickname,           0},
-	{ NTV2_XptLUT1Out,               NTV2_WgtLUT1,                NTV2_CHANNEL1,        kLUTNickname,                  0},
-	{ NTV2_XptCSC1VidRGB,            NTV2_WgtCSC1,                NTV2_CHANNEL1,        kCSCNickname,                  1},
-	{ NTV2_XptFrameBuffer1RGB,       NTV2_WgtFrameBuffer1,        NTV2_CHANNEL1,        kFramebufferNickname,          2},
-	{ NTV2_XptFrameSync1RGB,         NTV2_WgtFrameSync1,          NTV2_CHANNEL1,        kFrameSyncNickname,            1},
-	{ NTV2_XptFrameSync2RGB,         NTV2_WgtFrameSync2,          NTV2_CHANNEL2,        kFrameSyncNickname,            1},
-	{ NTV2_XptLUT2Out,               NTV2_WgtLUT2,                NTV2_CHANNEL2,        kLUTNickname,                  0},
-	{ NTV2_XptFrameBuffer2RGB,       NTV2_WgtFrameBuffer2,        NTV2_CHANNEL2,        kFramebufferNickname,          2},
-	{ NTV2_XptCSC2VidRGB,            NTV2_WgtCSC2,                NTV2_CHANNEL2,        kCSCNickname,                  1},
-	{ NTV2_XptMixer1VidRGB,          NTV2_WgtMixer1,              NTV2_CHANNEL1,        kMixerNickname,                1},
-	{ NTV2_XptHDMIIn1RGB,            NTV2_WgtHDMIIn1v3,           NTV2_CHANNEL1,        kHDMINickname,                 2},
-	{ NTV2_XptFrameBuffer3RGB,       NTV2_WgtFrameBuffer3,        NTV2_CHANNEL3,        kFramebufferNickname,          2},
-	{ NTV2_XptFrameBuffer4RGB,       NTV2_WgtFrameBuffer4,        NTV2_CHANNEL4,        kFramebufferNickname,          2},
-	{ NTV2_XptDuallinkIn2,           NTV2_WgtDualLinkV2In2,       NTV2_CHANNEL2,        kDualLinkInNickname,           0},
-	{ NTV2_XptLUT3Out,               NTV2_WgtLUT3,                NTV2_CHANNEL3,        kLUTNickname,                  0},
-	{ NTV2_XptLUT4Out,               NTV2_WgtLUT4,                NTV2_CHANNEL4,        kLUTNickname,                  0},
-	{ NTV2_XptLUT5Out,               NTV2_WgtLUT5,                NTV2_CHANNEL5,        kLUTNickname,                  0},
-	{ NTV2_XptCSC5VidRGB,            NTV2_WgtCSC5,                NTV2_CHANNEL5,        kCSCNickname,                  2},
-	{ NTV2_XptDuallinkIn3,           NTV2_WgtDualLinkV2In3,       NTV2_CHANNEL3,        kDualLinkInNickname,           0},
-	{ NTV2_XptDuallinkIn4,           NTV2_WgtDualLinkV2In4,       NTV2_CHANNEL4,        kDualLinkInNickname,           0},
-	{ NTV2_XptCSC3VidRGB,            NTV2_WgtCSC3,                NTV2_CHANNEL3,        kCSCNickname,                  2},
-	{ NTV2_XptCSC4VidRGB,            NTV2_WgtCSC4,                NTV2_CHANNEL4,        kCSCNickname,                  2},
-	{ NTV2_Xpt3DLUT1RGB,             NTV2_Wgt3DLUT1,              NTV2_CHANNEL1,        kLUT3DNickname,                1},
-	{ NTV2_XptHDMIIn1Q2RGB,          NTV2_WgtHDMIIn1v3,           NTV2_CHANNEL1,        kHDMINickname,                 1},
-	{ NTV2_XptHDMIIn1Q3RGB,          NTV2_WgtHDMIIn1v3,           NTV2_CHANNEL1,        kHDMINickname,                 2},
-	{ NTV2_XptHDMIIn1Q4RGB,          NTV2_WgtHDMIIn1v3,           NTV2_CHANNEL1,        kHDMINickname,                 3},
-	{ NTV2_Xpt4KDownConverterOutRGB, NTV2_Wgt4KDownConverter,     NTV2_CHANNEL1,        k4KDownConvertNickname,        1},
-	{ NTV2_XptDuallinkIn5,           NTV2_WgtDualLinkV2In5,       NTV2_CHANNEL5,        kDualLinkInNickname,           0},
-	{ NTV2_XptDuallinkIn6,           NTV2_WgtDualLinkV2In6,       NTV2_CHANNEL6,        kDualLinkInNickname,           0},
-	{ NTV2_XptDuallinkIn7,           NTV2_WgtDualLinkV2In7,       NTV2_CHANNEL7,        kDualLinkInNickname,           0},
-	{ NTV2_XptDuallinkIn8,           NTV2_WgtDualLinkV2In8,       NTV2_CHANNEL8,        kDualLinkInNickname,           0},
-	{ NTV2_XptFrameBuffer5RGB,       NTV2_WgtFrameBuffer5,        NTV2_CHANNEL5,        kFramebufferNickname,          2},
-	{ NTV2_XptFrameBuffer6RGB,       NTV2_WgtFrameBuffer6,        NTV2_CHANNEL6,        kFramebufferNickname,          2},
-	{ NTV2_XptFrameBuffer7RGB,       NTV2_WgtFrameBuffer7,        NTV2_CHANNEL7,        kFramebufferNickname,          2},
-	{ NTV2_XptFrameBuffer8RGB,       NTV2_WgtFrameBuffer8,        NTV2_CHANNEL8,        kFramebufferNickname,          2},
-	{ NTV2_XptCSC6VidRGB,            NTV2_WgtCSC6,                NTV2_CHANNEL6,        kCSCNickname,                  1},
-	{ NTV2_XptCSC7VidRGB,            NTV2_WgtCSC7,                NTV2_CHANNEL7,        kCSCNickname,                  1},
-	{ NTV2_XptCSC8VidRGB,            NTV2_WgtCSC8,                NTV2_CHANNEL8,        kCSCNickname,                  1},
-	{ NTV2_XptLUT6Out,               NTV2_WgtLUT6,                NTV2_CHANNEL6,        kLUTNickname,                  0},
-	{ NTV2_XptLUT7Out,               NTV2_WgtLUT7,                NTV2_CHANNEL7,        kLUTNickname,                  0},
-	{ NTV2_XptLUT8Out,               NTV2_WgtLUT8,                NTV2_CHANNEL8,        kLUTNickname,                  0},
-	{ NTV2_Xpt425Mux1ARGB,           NTV2_Wgt425Mux1,             NTV2_CHANNEL1,        kTSIMuxNickname,               2},
-	{ NTV2_Xpt425Mux1BRGB,           NTV2_Wgt425Mux1,             NTV2_CHANNEL1,        kTSIMuxNickname,               3},
-	{ NTV2_Xpt425Mux2ARGB,           NTV2_Wgt425Mux2,             NTV2_CHANNEL2,        kTSIMuxNickname,               2},
-	{ NTV2_Xpt425Mux2BRGB,           NTV2_Wgt425Mux2,             NTV2_CHANNEL2,        kTSIMuxNickname,               3},
-	{ NTV2_Xpt425Mux3ARGB,           NTV2_Wgt425Mux3,             NTV2_CHANNEL3,        kTSIMuxNickname,               2},
-	{ NTV2_Xpt425Mux3BRGB,           NTV2_Wgt425Mux3,             NTV2_CHANNEL3,        kTSIMuxNickname,               3},
-	{ NTV2_Xpt425Mux4ARGB,           NTV2_Wgt425Mux4,             NTV2_CHANNEL4,        kTSIMuxNickname,               2},
-	{ NTV2_Xpt425Mux4BRGB,           NTV2_Wgt425Mux4,             NTV2_CHANNEL4,        kTSIMuxNickname,               3},
-	{ NTV2_XptFrameBuffer1_DS2RGB,   NTV2_WgtFrameBuffer1,        NTV2_CHANNEL1,        kFramebufferNickname,          3},
-	{ NTV2_XptFrameBuffer2_DS2RGB,   NTV2_WgtFrameBuffer2,        NTV2_CHANNEL2,        kFramebufferNickname,          3},
-	{ NTV2_XptFrameBuffer3_DS2RGB,   NTV2_WgtFrameBuffer3,        NTV2_CHANNEL3,        kFramebufferNickname,          3},
-	{ NTV2_XptFrameBuffer4_DS2RGB,   NTV2_WgtFrameBuffer4,        NTV2_CHANNEL4,        kFramebufferNickname,          3},
-	{ NTV2_XptFrameBuffer5_DS2RGB,   NTV2_WgtFrameBuffer5,        NTV2_CHANNEL5,        kFramebufferNickname,          3},
-	{ NTV2_XptFrameBuffer6_DS2RGB,   NTV2_WgtFrameBuffer6,        NTV2_CHANNEL6,        kFramebufferNickname,          3},
-	{ NTV2_XptFrameBuffer7_DS2RGB,   NTV2_WgtFrameBuffer7,        NTV2_CHANNEL7,        kFramebufferNickname,          3},
-	{ NTV2_XptFrameBuffer8_DS2RGB,   NTV2_WgtFrameBuffer8,        NTV2_CHANNEL8,        kFramebufferNickname,          3},
-	{ NTV2_XptHDMIIn2RGB,            NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 0},
-	{ NTV2_XptHDMIIn2Q2RGB,          NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 1},
-	{ NTV2_XptHDMIIn2Q3RGB,          NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 2},
-	{ NTV2_XptHDMIIn2Q4RGB,          NTV2_WgtHDMIIn2v4,           NTV2_CHANNEL2,        kHDMINickname,                 3},
-	{ NTV2_XptHDMIIn3RGB,            NTV2_WgtHDMIIn3v4,           NTV2_CHANNEL3,        kHDMINickname,                 0},
-	{ NTV2_XptHDMIIn4RGB,            NTV2_WgtHDMIIn4v4,           NTV2_CHANNEL4,        kHDMINickname,                 0},
+	{ NTV2_OUTPUT_CROSSPOINT_INVALID, NTV2_WIDGET_INVALID, "", -1},
+	{ NTV2_XptBlack,                 NTV2_WgtUndefined,                   kBlackNickname,                0},
+	{ NTV2_XptSDIIn1,                NTV2_WgtSDIIn1,                      kSDINickname,                  0},
+	{ NTV2_XptSDIIn2,                NTV2_WgtSDIIn2,                      kSDINickname,                  0},
+	{ NTV2_XptLUT1YUV,               NTV2_WgtLUT1,                        kSDINickname,                  0},
+	{ NTV2_XptCSC1VidYUV,            NTV2_WgtCSC1,                        kCSCNickname,                  0},
+	{ NTV2_XptConversionModule,      NTV2_WgtUpDownConverter1,            kUpDownConvertNickname,        0},
+	{ NTV2_XptCompressionModule,     NTV2_WgtCompression1,                kCompressionNickname,          0},
+	{ NTV2_XptFrameBuffer1YUV,       NTV2_WgtFrameBuffer1,                kFramebufferNickname,          0},
+	{ NTV2_XptFrameSync1YUV,         NTV2_WgtFrameSync1,                  kFrameSyncNickname,            0},
+	{ NTV2_XptFrameSync2YUV,         NTV2_WgtFrameSync2,                  kFrameSyncNickname,            0},
+	{ NTV2_XptDuallinkOut1,          NTV2_WgtDualLinkV2Out1,              kDualLinkOutNickname,          0},
+	{ NTV2_XptCSC1KeyYUV,            NTV2_WgtCSC1,                        kCSCNickname,                  2},
+	{ NTV2_XptFrameBuffer2YUV,       NTV2_WgtFrameBuffer2,                kFramebufferNickname,          0},
+	{ NTV2_XptCSC2VidYUV,            NTV2_WgtCSC2,                        kCSCNickname,                  0},
+	{ NTV2_XptCSC2KeyYUV,            NTV2_WgtCSC2,                        kCSCNickname,                  2},
+	{ NTV2_XptMixer1VidYUV,          NTV2_WgtMixer1,                      kMixerNickname,                0},
+	{ NTV2_XptMixer1KeyYUV,          NTV2_WgtMixer1,                      kMixerNickname,                1},
+	{ NTV2_XptMultiLinkOut1DS1,      NTV2_WgtMultiLinkOut1,               kMultiLinkNickname,            0},
+	{ NTV2_XptMultiLinkOut1DS2,      NTV2_WgtMultiLinkOut1,               kMultiLinkNickname,            1},
+	{ NTV2_XptAnalogIn,              NTV2_WgtAnalogIn1,                   kAnalogNickname,               0},
+	{ NTV2_XptHDMIIn1,               NTV2_WgtHDMIIn1,                     kHDMINickname,                 0},
+	{ NTV2_XptMultiLinkOut1DS3,      NTV2_WgtMultiLinkOut1,               kMultiLinkNickname,            2},
+	{ NTV2_XptMultiLinkOut1DS4,      NTV2_WgtMultiLinkOut1,               kMultiLinkNickname,            3},
+	{ NTV2_XptMultiLinkOut2DS1,      NTV2_WgtMultiLinkOut2,               kMultiLinkNickname,            0},
+	{ NTV2_XptMultiLinkOut2DS2,      NTV2_WgtMultiLinkOut2,               kMultiLinkNickname,            1},
+	{ NTV2_XptDuallinkOut2,          NTV2_WgtDualLinkV2Out2,              kDualLinkOutNickname,          0},
+	{ NTV2_XptTestPatternYUV,        NTV2_WgtTestPattern1,                kTestPatternNickname,          0},
+	{ NTV2_XptSDIIn1DS2,             NTV2_Wgt3GSDIIn1,                    kSDINickname,                  1},
+	{ NTV2_XptSDIIn2DS2,             NTV2_Wgt3GSDIIn2,                    kSDINickname,                  1},
+	{ NTV2_XptMixer2VidYUV,          NTV2_WgtMixer2,                      kMixerNickname,                0},
+	{ NTV2_XptMixer2KeyYUV,          NTV2_WgtMixer2,                      kMixerNickname,                1},
+	{ NTV2_XptStereoCompressorOut,   NTV2_WgtStereoCompressor,            kStereoCompNickname,           0},
+	{ NTV2_XptFrameBuffer3YUV,       NTV2_WgtFrameBuffer3,                kFramebufferNickname,          0},
+	{ NTV2_XptFrameBuffer4YUV,       NTV2_WgtFrameBuffer4,                kFramebufferNickname,          0},
+	{ NTV2_XptDuallinkOut1DS2,       NTV2_WgtDualLinkV2Out1,              kDualLinkOutNickname,          1},
+	{ NTV2_XptDuallinkOut2DS2,       NTV2_WgtDualLinkV2Out2,              kDualLinkOutNickname,          1},
+	{ NTV2_XptCSC5VidYUV,            NTV2_WgtCSC5,                        kCSCNickname,                  0},
+	{ NTV2_XptCSC5KeyYUV,            NTV2_WgtCSC5,                        kCSCNickname,                  1},
+	{ NTV2_XptMultiLinkOut2DS3,      NTV2_WgtMultiLinkOut2,               kMultiLinkNickname,            2},
+	{ NTV2_XptMultiLinkOut2DS4,      NTV2_WgtMultiLinkOut2,               kMultiLinkNickname,            3},
+	{ NTV2_XptSDIIn3,                NTV2_Wgt3GSDIIn3,                    kSDINickname,                  0},
+	{ NTV2_XptSDIIn4,                NTV2_Wgt3GSDIIn4,                    kSDINickname,                  0},
+	{ NTV2_XptSDIIn3DS2,             NTV2_Wgt3GSDIIn3,                    kSDINickname,                  1},
+	{ NTV2_XptSDIIn4DS2,             NTV2_Wgt3GSDIIn4,                    kSDINickname,                  1},
+	{ NTV2_XptDuallinkOut3,          NTV2_WgtDualLinkV2Out3,              kDualLinkOutNickname,          0},
+	{ NTV2_XptDuallinkOut3DS2,       NTV2_WgtDualLinkV2Out3,              kDualLinkOutNickname,          1},
+	{ NTV2_XptDuallinkOut4,          NTV2_WgtDualLinkV2Out4,              kDualLinkOutNickname,          0},
+	{ NTV2_XptDuallinkOut4DS2,       NTV2_WgtDualLinkV2Out4,              kDualLinkOutNickname,          1},
+	{ NTV2_XptCSC3VidYUV,            NTV2_WgtCSC3,                        kCSCNickname,                  0},
+	{ NTV2_XptCSC3KeyYUV,            NTV2_WgtCSC3,                        kCSCNickname,                  2},
+	{ NTV2_XptCSC4VidYUV,            NTV2_WgtCSC4,                        kCSCNickname,                  0},
+	{ NTV2_XptCSC4KeyYUV,            NTV2_WgtCSC4,                        kCSCNickname,                  2},
+	{ NTV2_XptDuallinkOut5,          NTV2_WgtDualLinkV2Out5,              kDualLinkOutNickname,          0},
+	{ NTV2_XptDuallinkOut5DS2,       NTV2_WgtDualLinkV2Out5,              kDualLinkOutNickname,          1},
+	{ NTV2_Xpt3DLUT1YUV,             NTV2_Wgt3DLUT1,                      kLUT3DNickname,                0},
+	{ NTV2_XptHDMIIn1Q2,             NTV2_WgtHDMIIn1v3,                   kHDMINickname,                 1},
+	{ NTV2_XptHDMIIn1Q3,             NTV2_WgtHDMIIn1v3,                   kHDMINickname,                 2},
+	{ NTV2_XptHDMIIn1Q4,             NTV2_WgtHDMIIn1v3,                   kHDMINickname,                 3},
+	{ NTV2_Xpt4KDownConverterOut,    NTV2_Wgt4KDownConverter,             k4KDownConvertNickname,        0},
+	{ NTV2_XptSDIIn5,                NTV2_Wgt3GSDIIn5,                    kSDINickname,                  0},
+	{ NTV2_XptSDIIn6,                NTV2_Wgt3GSDIIn6,                    kSDINickname,                  0},
+	{ NTV2_XptSDIIn5DS2,             NTV2_Wgt3GSDIIn5,                    kSDINickname,                  1},
+	{ NTV2_XptSDIIn6DS2,             NTV2_Wgt3GSDIIn6,                    kSDINickname,                  1},
+	{ NTV2_XptSDIIn7,                NTV2_Wgt3GSDIIn7,                    kSDINickname,                  0},
+	{ NTV2_XptSDIIn8,                NTV2_Wgt3GSDIIn8,                    kSDINickname,                  0},
+	{ NTV2_XptSDIIn7DS2,             NTV2_Wgt3GSDIIn7,                    kSDINickname,                  1},
+	{ NTV2_XptSDIIn8DS2,             NTV2_Wgt3GSDIIn8,                    kSDINickname,                  1},
+	{ NTV2_XptFrameBuffer5YUV,       NTV2_WgtFrameBuffer5,                kFramebufferNickname,          0},
+	{ NTV2_XptFrameBuffer6YUV,       NTV2_WgtFrameBuffer6,                kFramebufferNickname,          0},
+	{ NTV2_XptFrameBuffer7YUV,       NTV2_WgtFrameBuffer7,                kFramebufferNickname,          0},
+	{ NTV2_XptFrameBuffer8YUV,       NTV2_WgtFrameBuffer8,                kFramebufferNickname,          0},
+	{ NTV2_XptMixer3VidYUV,          NTV2_WgtMixer3,                      kMixerNickname,                0},
+	{ NTV2_XptMixer3KeyYUV,          NTV2_WgtMixer3,                      kMixerNickname,                1},
+	{ NTV2_XptMixer4VidYUV,          NTV2_WgtMixer4,                      kMixerNickname,                0},
+	{ NTV2_XptMixer4KeyYUV,          NTV2_WgtMixer4,                      kMixerNickname,                1},
+	{ NTV2_XptCSC6VidYUV,            NTV2_WgtCSC6,                        kCSCNickname,                  0},
+	{ NTV2_XptCSC6KeyYUV,            NTV2_WgtCSC6,                        kCSCNickname,                  1},
+	{ NTV2_XptCSC7VidYUV,            NTV2_WgtCSC7,                        kCSCNickname,                  0},
+	{ NTV2_XptCSC7KeyYUV,            NTV2_WgtCSC7,                        kCSCNickname,                  1},
+	{ NTV2_XptCSC8VidYUV,            NTV2_WgtCSC8,                        kCSCNickname,                  0},
+	{ NTV2_XptCSC8KeyYUV,            NTV2_WgtCSC8,                        kCSCNickname,                  1},
+	{ NTV2_XptDuallinkOut6,          NTV2_WgtDualLinkV2Out6,              kDualLinkOutNickname,          0},
+	{ NTV2_XptDuallinkOut6DS2,       NTV2_WgtDualLinkV2Out6,              kDualLinkOutNickname,          1},
+	{ NTV2_XptDuallinkOut7,          NTV2_WgtDualLinkV2Out7,              kDualLinkOutNickname,          0},
+	{ NTV2_XptDuallinkOut7DS2,       NTV2_WgtDualLinkV2Out7,              kDualLinkOutNickname,          1},
+	{ NTV2_XptDuallinkOut8,          NTV2_WgtDualLinkV2Out8,              kDualLinkOutNickname,          0},
+	{ NTV2_XptDuallinkOut8DS2,       NTV2_WgtDualLinkV2Out8,              kDualLinkOutNickname,          1},
+	{ NTV2_Xpt425Mux1AYUV,           NTV2_Wgt425Mux1,                     kTSIMuxNickname,               0},
+	{ NTV2_Xpt425Mux1BYUV,           NTV2_Wgt425Mux1,                     kTSIMuxNickname,               1},
+	{ NTV2_Xpt425Mux2AYUV,           NTV2_Wgt425Mux2,                     kTSIMuxNickname,               0},
+	{ NTV2_Xpt425Mux2BYUV,           NTV2_Wgt425Mux2,                     kTSIMuxNickname,               1},
+	{ NTV2_Xpt425Mux3AYUV,           NTV2_Wgt425Mux3,                     kTSIMuxNickname,               0},
+	{ NTV2_Xpt425Mux3BYUV,           NTV2_Wgt425Mux3,                     kTSIMuxNickname,               1},
+	{ NTV2_Xpt425Mux4AYUV,           NTV2_Wgt425Mux4,                     kTSIMuxNickname,               0},
+	{ NTV2_Xpt425Mux4BYUV,           NTV2_Wgt425Mux4,                     kTSIMuxNickname,               1},
+	{ NTV2_XptFrameBuffer1_DS2YUV,   NTV2_WgtFrameBuffer1,                kFramebufferNickname,          1},
+	{ NTV2_XptFrameBuffer2_DS2YUV,   NTV2_WgtFrameBuffer2,                kFramebufferNickname,          1},
+	{ NTV2_XptFrameBuffer3_DS2YUV,   NTV2_WgtFrameBuffer3,                kFramebufferNickname,          1},
+	{ NTV2_XptFrameBuffer4_DS2YUV,   NTV2_WgtFrameBuffer4,                kFramebufferNickname,          1},
+	{ NTV2_XptFrameBuffer5_DS2YUV,   NTV2_WgtFrameBuffer5,                kFramebufferNickname,          1},
+	{ NTV2_XptFrameBuffer6_DS2YUV,   NTV2_WgtFrameBuffer6,                kFramebufferNickname,          1},
+	{ NTV2_XptFrameBuffer7_DS2YUV,   NTV2_WgtFrameBuffer7,                kFramebufferNickname,          1},
+	{ NTV2_XptFrameBuffer8_DS2YUV,   NTV2_WgtFrameBuffer8,                kFramebufferNickname,          1},
+	{ NTV2_XptHDMIIn2,               NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 0},
+	{ NTV2_XptHDMIIn2Q2,             NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 1},
+	{ NTV2_XptHDMIIn2Q3,             NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 2},
+	{ NTV2_XptHDMIIn2Q4,             NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 3},
+	{ NTV2_XptHDMIIn3,               NTV2_WgtHDMIIn3v4,                   kHDMINickname,                 0},
+	{ NTV2_XptHDMIIn4,               NTV2_WgtHDMIIn4v4,                   kHDMINickname,                 0},
+	{ NTV2_XptDuallinkIn1,           NTV2_WgtDualLinkV2In1,               kDualLinkInNickname,           0},
+	{ NTV2_XptLUT1Out,               NTV2_WgtLUT1,                        kLUTNickname,                  0},
+	{ NTV2_XptCSC1VidRGB,            NTV2_WgtCSC1,                        kCSCNickname,                  1},
+	{ NTV2_XptFrameBuffer1RGB,       NTV2_WgtFrameBuffer1,                kFramebufferNickname,          2},
+	{ NTV2_XptFrameSync1RGB,         NTV2_WgtFrameSync1,                  kFrameSyncNickname,            1},
+	{ NTV2_XptFrameSync2RGB,         NTV2_WgtFrameSync2,                  kFrameSyncNickname,            1},
+	{ NTV2_XptLUT2Out,               NTV2_WgtLUT2,                        kLUTNickname,                  0},
+	{ NTV2_XptFrameBuffer2RGB,       NTV2_WgtFrameBuffer2,                kFramebufferNickname,          2},
+	{ NTV2_XptCSC2VidRGB,            NTV2_WgtCSC2,                        kCSCNickname,                  1},
+	{ NTV2_XptMixer1VidRGB,          NTV2_WgtMixer1,                      kMixerNickname,                1},
+	{ NTV2_XptHDMIIn1RGB,            NTV2_WgtHDMIIn1v3,                   kHDMINickname,                 2},
+	{ NTV2_XptFrameBuffer3RGB,       NTV2_WgtFrameBuffer3,                kFramebufferNickname,          2},
+	{ NTV2_XptFrameBuffer4RGB,       NTV2_WgtFrameBuffer4,                kFramebufferNickname,          2},
+	{ NTV2_XptDuallinkIn2,           NTV2_WgtDualLinkV2In2,               kDualLinkInNickname,           0},
+	{ NTV2_XptLUT3Out,               NTV2_WgtLUT3,                        kLUTNickname,                  0},
+	{ NTV2_XptLUT4Out,               NTV2_WgtLUT4,                        kLUTNickname,                  0},
+	{ NTV2_XptLUT5Out,               NTV2_WgtLUT5,                        kLUTNickname,                  0},
+	{ NTV2_XptCSC5VidRGB,            NTV2_WgtCSC5,                        kCSCNickname,                  2},
+	{ NTV2_XptDuallinkIn3,           NTV2_WgtDualLinkV2In3,               kDualLinkInNickname,           0},
+	{ NTV2_XptDuallinkIn4,           NTV2_WgtDualLinkV2In4,               kDualLinkInNickname,           0},
+	{ NTV2_XptCSC3VidRGB,            NTV2_WgtCSC3,                        kCSCNickname,                  2},
+	{ NTV2_XptCSC4VidRGB,            NTV2_WgtCSC4,                        kCSCNickname,                  2},
+	{ NTV2_Xpt3DLUT1RGB,             NTV2_Wgt3DLUT1,                      kLUT3DNickname,                1},
+	{ NTV2_XptHDMIIn1Q2RGB,          NTV2_WgtHDMIIn1v3,                   kHDMINickname,                 1},
+	{ NTV2_XptHDMIIn1Q3RGB,          NTV2_WgtHDMIIn1v3,                   kHDMINickname,                 2},
+	{ NTV2_XptHDMIIn1Q4RGB,          NTV2_WgtHDMIIn1v3,                   kHDMINickname,                 3},
+	{ NTV2_Xpt4KDownConverterOutRGB, NTV2_Wgt4KDownConverter,             k4KDownConvertNickname,        1},
+	{ NTV2_XptDuallinkIn5,           NTV2_WgtDualLinkV2In5,               kDualLinkInNickname,           0},
+	{ NTV2_XptDuallinkIn6,           NTV2_WgtDualLinkV2In6,               kDualLinkInNickname,           0},
+	{ NTV2_XptDuallinkIn7,           NTV2_WgtDualLinkV2In7,               kDualLinkInNickname,           0},
+	{ NTV2_XptDuallinkIn8,           NTV2_WgtDualLinkV2In8,               kDualLinkInNickname,           0},
+	{ NTV2_XptFrameBuffer5RGB,       NTV2_WgtFrameBuffer5,                kFramebufferNickname,          2},
+	{ NTV2_XptFrameBuffer6RGB,       NTV2_WgtFrameBuffer6,                kFramebufferNickname,          2},
+	{ NTV2_XptFrameBuffer7RGB,       NTV2_WgtFrameBuffer7,                kFramebufferNickname,          2},
+	{ NTV2_XptFrameBuffer8RGB,       NTV2_WgtFrameBuffer8,                kFramebufferNickname,          2},
+	{ NTV2_XptCSC6VidRGB,            NTV2_WgtCSC6,                        kCSCNickname,                  1},
+	{ NTV2_XptCSC7VidRGB,            NTV2_WgtCSC7,                        kCSCNickname,                  1},
+	{ NTV2_XptCSC8VidRGB,            NTV2_WgtCSC8,                        kCSCNickname,                  1},
+	{ NTV2_XptLUT6Out,               NTV2_WgtLUT6,                        kLUTNickname,                  0},
+	{ NTV2_XptLUT7Out,               NTV2_WgtLUT7,                        kLUTNickname,                  0},
+	{ NTV2_XptLUT8Out,               NTV2_WgtLUT8,                        kLUTNickname,                  0},
+	{ NTV2_Xpt425Mux1ARGB,           NTV2_Wgt425Mux1,                     kTSIMuxNickname,               2},
+	{ NTV2_Xpt425Mux1BRGB,           NTV2_Wgt425Mux1,                     kTSIMuxNickname,               3},
+	{ NTV2_Xpt425Mux2ARGB,           NTV2_Wgt425Mux2,                     kTSIMuxNickname,               2},
+	{ NTV2_Xpt425Mux2BRGB,           NTV2_Wgt425Mux2,                     kTSIMuxNickname,               3},
+	{ NTV2_Xpt425Mux3ARGB,           NTV2_Wgt425Mux3,                     kTSIMuxNickname,               2},
+	{ NTV2_Xpt425Mux3BRGB,           NTV2_Wgt425Mux3,                     kTSIMuxNickname,               3},
+	{ NTV2_Xpt425Mux4ARGB,           NTV2_Wgt425Mux4,                     kTSIMuxNickname,               2},
+	{ NTV2_Xpt425Mux4BRGB,           NTV2_Wgt425Mux4,                     kTSIMuxNickname,               3},
+	{ NTV2_XptFrameBuffer1_DS2RGB,   NTV2_WgtFrameBuffer1,                kFramebufferNickname,          3},
+	{ NTV2_XptFrameBuffer2_DS2RGB,   NTV2_WgtFrameBuffer2,                kFramebufferNickname,          3},
+	{ NTV2_XptFrameBuffer3_DS2RGB,   NTV2_WgtFrameBuffer3,                kFramebufferNickname,          3},
+	{ NTV2_XptFrameBuffer4_DS2RGB,   NTV2_WgtFrameBuffer4,                kFramebufferNickname,          3},
+	{ NTV2_XptFrameBuffer5_DS2RGB,   NTV2_WgtFrameBuffer5,                kFramebufferNickname,          3},
+	{ NTV2_XptFrameBuffer6_DS2RGB,   NTV2_WgtFrameBuffer6,                kFramebufferNickname,          3},
+	{ NTV2_XptFrameBuffer7_DS2RGB,   NTV2_WgtFrameBuffer7,                kFramebufferNickname,          3},
+	{ NTV2_XptFrameBuffer8_DS2RGB,   NTV2_WgtFrameBuffer8,                kFramebufferNickname,          3},
+	{ NTV2_XptHDMIIn2RGB,            NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 0},
+	{ NTV2_XptHDMIIn2Q2RGB,          NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 1},
+	{ NTV2_XptHDMIIn2Q3RGB,          NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 2},
+	{ NTV2_XptHDMIIn2Q4RGB,          NTV2_WgtHDMIIn2v4,                   kHDMINickname,                 3},
+	{ NTV2_XptHDMIIn3RGB,            NTV2_WgtHDMIIn3v4,                   kHDMINickname,                 0},
+	{ NTV2_XptHDMIIn4RGB,            NTV2_WgtHDMIIn4v4,                   kHDMINickname,                 0},
 };
 // clang-format on
 
@@ -349,7 +350,9 @@ bool WidgetInputSocket::Find(const std::string &name, NTV2Channel channel,
 			     int32_t datastream, WidgetInputSocket &inp)
 {
 	for (const auto &in : kWidgetInputSockets) {
-		if (name == in.name && channel == in.channel &&
+		if (name == in.name &&
+		    channel == CNTV2SignalRouter::WidgetIDToChannel(
+				       in.widget_id) &&
 		    datastream == in.datastream_index) {
 			inp = in;
 			return true;
@@ -389,7 +392,8 @@ NTV2Channel WidgetInputSocket::InputXptChannel(InputXpt xpt)
 	NTV2Channel channel = NTV2_CHANNEL_INVALID;
 	for (auto &x : kWidgetInputSockets) {
 		if (x.id == xpt) {
-			channel = x.channel;
+			channel = CNTV2SignalRouter::WidgetIDToChannel(
+				x.widget_id);
 			break;
 		}
 	}
@@ -415,7 +419,9 @@ bool WidgetOutputSocket::Find(const std::string &name, NTV2Channel channel,
 	// 	  << ", chan = " << NTV2ChannelToString(channel)
 	// 	  << ", datastream = " << datastream << std::endl;
 	for (const auto &wo : kWidgetOutputSockets) {
-		if (name == wo.name && channel == wo.channel &&
+		if (name == wo.name &&
+		    channel == CNTV2SignalRouter::WidgetIDToChannel(
+				       wo.widget_id) &&
 		    datastream == wo.datastream_index) {
 			out = wo;
 			return true;
@@ -455,7 +461,8 @@ NTV2Channel WidgetOutputSocket::OutputXptChannel(OutputXpt xpt)
 	NTV2Channel channel = NTV2_CHANNEL_INVALID;
 	for (auto &x : kWidgetOutputSockets) {
 		if (x.id == xpt) {
-			channel = x.channel;
+			channel = CNTV2SignalRouter::WidgetIDToChannel(
+				x.widget_id);
 			break;
 		}
 	}

+ 0 - 2
plugins/aja/aja-widget-io.hpp

@@ -11,7 +11,6 @@ using InputXpt = NTV2InputCrosspointID;   // dest
 struct WidgetInputSocket {
 	InputXpt id;
 	NTV2WidgetID widget_id;
-	NTV2Channel channel;
 	const char *name;
 	int32_t datastream_index;
 
@@ -28,7 +27,6 @@ struct WidgetInputSocket {
 struct WidgetOutputSocket {
 	OutputXpt id;
 	NTV2WidgetID widget_id;
-	NTV2Channel channel;
 	const char *name;
 	int32_t datastream_index;
 

+ 3 - 1
plugins/aja/data/locale/en-US.ini

@@ -12,4 +12,6 @@ AutoStart="Auto start on launch"
 Buffering="Use Buffering"
 DeactivateWhenNotShowing="Deactivate when not showing"
 IOSelect="Select..."
-SDI4KTransport="SDI 4K Transport"
+SDITransport="SDI Transport"
+SDITransport4K="SDI 4K Transport"
+Auto="Auto"

+ 16 - 1
plugins/aja/main.cpp

@@ -20,8 +20,9 @@ bool obs_module_load(void)
 {
 	CNTV2DeviceScanner scanner;
 	auto numDevices = scanner.GetNumDevices();
-
 	if (numDevices == 0) {
+		blog(LOG_WARNING,
+		     "No AJA devices found, skipping loading AJA plugin");
 		return false;
 	}
 
@@ -36,6 +37,20 @@ bool obs_module_load(void)
 	return true;
 }
 
+void obs_module_post_load(void)
+{
+	struct calldata params = {0};
+	auto cardManager = &aja::CardManager::Instance();
+	auto num = cardManager->NumCardEntries();
+	blog(LOG_WARNING, "aja main card manager: %lu", cardManager);
+	blog(LOG_WARNING, "NUM CARDS: %lu", num);
+
+	calldata_set_ptr(&params, "card_manager", (void *)cardManager);
+	auto signal_handler = obs_get_signal_handler();
+	signal_handler_signal(signal_handler, "aja_loaded", &params);
+	calldata_free(&params);
+}
+
 void obs_module_unload(void)
 {
 	aja::CardManager::Instance().ClearCardEntries();

+ 0 - 22
plugins/aja/routing/hdmi_rgb_capture.h

@@ -1,22 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<HDMIWireFormat, RoutingConfig>
-	kHDMIRGBCaptureConfigs = {{HDMIWireFormat::HD_RGB_LFR,
-				   {
-					   NTV2_MODE_CAPTURE,
-					   1,
-					   1,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   "hdmi[{ch1}][0]->fb[{ch1}][0];",
-				   }}};

+ 0 - 29
plugins/aja/routing/hdmi_rgb_display.h

@@ -1,29 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<HDMIWireFormat, RoutingConfig>
-	kHDMIRGBDisplayConfigs = {{HDMIWireFormat::HD_RGB_LFR,
-				   {NTV2_MODE_DISPLAY, 1, 1, true, false, false,
-				    false, false, false, false, false, false,
-				    false, "fb[{ch1}][0]->hdmi[0][0];"}},
-				  {HDMIWireFormat::TTAP_PRO,
-				   {
-					   NTV2_MODE_DISPLAY,
-					   1,
-					   1,
-					   true,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   false,
-					   "fb[{ch1}][2]->dlo[{ch1}][0];"
-					   "dlo[{ch1}][0]->sdi[{ch1}][0];"
-					   "dlo[{ch1}][1]->sdi[{ch1}][1];"
-					   "fb[{ch1}][2]->hdmi[{ch1}][0];",
-				   }}};

+ 0 - 48
plugins/aja/routing/hdmi_ycbcr_capture.h

@@ -1,48 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<HDMIWireFormat, RoutingConfig>
-	kHDMIYCbCrCaptureConfigs = {
-		{HDMIWireFormat::HD_YCBCR_LFR,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 1,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "hdmi[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{HDMIWireFormat::UHD_4K_YCBCR_LFR,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 2,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "hdmi[0][0]->tsi[{ch1}][0];"
-			 "hdmi[0][1]->tsi[{ch1}][1];"
-			 "hdmi[0][2]->tsi[{ch2}][0];"
-			 "hdmi[0][3]->tsi[{ch2}][1];"
-			 "tsi[{ch1}][0]->fb[{ch1}][0];"
-			 "tsi[{ch1}][1]->fb[{ch1}][1];"
-			 "tsi[{ch2}][0]->fb[{ch2}][0];"
-			 "tsi[{ch2}][1]->fb[{ch2}][1];",
-		 }},
-};

+ 0 - 64
plugins/aja/routing/hdmi_ycbcr_display.h

@@ -1,64 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<HDMIWireFormat, RoutingConfig>
-	kHDMIYCbCrDisplayConfigs = {{HDMIWireFormat::HD_YCBCR_LFR,
-				     {
-					     NTV2_MODE_DISPLAY,
-					     1,
-					     1,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     "fb[{ch1}][0]->hdmi[0][0];",
-				     }},
-				    {HDMIWireFormat::UHD_4K_YCBCR_LFR,
-				     {
-					     NTV2_MODE_DISPLAY,
-					     1,
-					     2,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     true,
-					     "fb[{ch1}][0]->tsi[{ch1}][0];"
-					     "fb[{ch1}][1]->tsi[{ch1}][1];"
-					     "fb[{ch2}][0]->tsi[{ch2}][0];"
-					     "fb[{ch2}][1]->tsi[{ch2}][1];"
-					     "tsi[{ch1}][0]->hdmi[0][0];"
-					     "tsi[{ch1}][1]->hdmi[0][1];"
-					     "tsi[{ch2}][0]->hdmi[0][2];"
-					     "tsi[{ch2}][1]->hdmi[0][3];",
-				     }},
-				    {HDMIWireFormat::TTAP_PRO,
-				     {
-					     NTV2_MODE_DISPLAY,
-					     1,
-					     1,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     false,
-					     "fb[{ch1}][0]->sdi[{ch1}][0];"
-					     "fb[{ch1}][0]->hdmi[{ch1}][0];",
-				     }}};

+ 0 - 467
plugins/aja/routing/sdi_rgb_capture.h

@@ -1,467 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<SDIWireFormat, RoutingConfig>
-	kSDIRGBCaptureConfigs = {
-		{
-			SDIWireFormat::SD_ST352,
-			{
-				NTV2_MODE_CAPTURE, // i/o mode
-				1,                 // num wires
-				1,                 // num framestores
-				false,             // enable 3G output?
-				false,             // enable 6G output?
-				false,             // enable 12G output?
-				false,             // convert 3Gb -> 3Ga input?
-				false,             // convert 3Ga -> 3Gb output?
-				false,             // convert RGB 3Ga output?
-				false,             // enable 3Gb output?
-				false,             // enable 4K Square Division?
-				false,             // enable 8K Square Division?
-				false, // enable two-sample-interleave?
-				"",
-			},
-		},
-		{SDIWireFormat::HD_720p_ST292,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 1,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_1080_ST292,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 1,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_1080_ST372_Dual,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 2,
-			 1,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch2}][0]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_720p_ST425_3Ga,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 1,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_3Ga,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 1,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_3Gb_DL,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 1,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_720p_ST425_3Gb,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_3Gb,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "dli[{ch1}][0]->fb[{ch1}][0];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_Dual_3Ga,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 2,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_Dual_3Gb,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 2,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "",
-		 }},
-		{SDIWireFormat::UHD4K_ST292_Quad_1_5_Squares,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 4,
-			 4,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->fb[{ch1}][0];"
-			 "sdi[{ch2}][0]->fb[{ch2}][0];"
-			 "sdi[{ch3}][0]->fb[{ch3}][0];"
-			 "sdi[{ch4}][0]->fb[{ch4}][0];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Ga_Squares,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 // Capture
-			 "sdi[{ch1}][0]->fb[{ch1}][0];"
-			 "sdi[{ch2}][0]->fb[{ch2}][0];"
-			 "sdi[{ch3}][0]->fb[{ch3}][0];"
-			 "sdi[{ch4}][0]->fb[{ch4}][0];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Gb_Squares,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-
-			 "sdi[{ch2}][0]->dli[{ch2}][0];"
-			 "sdi[{ch2}][1]->dli[{ch2}][1];"
-
-			 "sdi[{ch3}][0]->dli[{ch3}][0];"
-			 "sdi[{ch3}][1]->dli[{ch3}][1];"
-
-			 "sdi[{ch4}][0]->dli[{ch4}][0];"
-			 "sdi[{ch4}][1]->dli[{ch4}][1];"
-
-			 "dli[{ch1}][0]->fb[{ch1}][2];"
-			 "dli[{ch2}][0]->fb[{ch2}][2];"
-			 "dli[{ch3}][0]->fb[{ch3}][2];"
-			 "dli[{ch4}][0]->fb[{ch4}][2];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Dual_3Gb_2SI,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 2,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Ga_2SI,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 // SDI 1-4 -> Dual-Link 1-4
-			 // -> TSI Mux 1-2 -> Framestore 1-2
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "sdi[{ch2}][0]->dli[{ch2}][0];"
-			 "sdi[{ch2}][1]->dli[{ch2}][1];"
-			 "sdi[{ch3}][0]->dli[{ch3}][0];"
-			 "sdi[{ch3}][1]->dli[{ch3}][1];"
-			 "sdi[{ch4}][0]->dli[{ch4}][0];"
-			 "sdi[{ch4}][1]->dli[{ch4}][1];"
-
-			 "dli[{ch1}][0]->tsi[{ch1}][0];"
-			 "dli[{ch2}][0]->tsi[{ch1}][1];"
-			 "dli[{ch3}][0]->tsi[{ch2}][0];"
-			 "dli[{ch4}][0]->tsi[{ch2}][1];"
-
-			 "tsi[{ch1}][0]->fb[{ch1}][0];"
-			 "tsi[{ch1}][1]->fb[{ch1}][1];"
-			 "tsi[{ch2}][0]->fb[{ch2}][0];"
-			 "tsi[{ch2}][1]->fb[{ch2}][1];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Gb_2SI,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 // SDI 1-4 -> Dual-Link 1-4
-			 // -> TSI Mux 1-2 -> Framestore 1-2
-			 "sdi[{ch1}][0]->dli[{ch1}][0];"
-			 "sdi[{ch1}][1]->dli[{ch1}][1];"
-			 "sdi[{ch2}][0]->dli[{ch2}][0];"
-			 "sdi[{ch2}][1]->dli[{ch2}][1];"
-			 "sdi[{ch3}][0]->dli[{ch3}][0];"
-			 "sdi[{ch3}][1]->dli[{ch3}][1];"
-			 "sdi[{ch4}][0]->dli[{ch4}][0];"
-			 "sdi[{ch4}][1]->dli[{ch4}][1];"
-
-			 "dli[{ch1}][0]->tsi[{ch1}][0];"
-			 "dli[{ch2}][0]->tsi[{ch1}][1];"
-			 "dli[{ch3}][0]->tsi[{ch2}][0];"
-			 "dli[{ch4}][0]->tsi[{ch2}][1];"
-
-			 "tsi[{ch1}][0]->fb[{ch1}][0];"
-			 "tsi[{ch1}][1]->fb[{ch1}][1];"
-			 "tsi[{ch2}][0]->fb[{ch2}][0];"
-			 "tsi[{ch2}][1]->fb[{ch2}][1];",
-		 }},
-		{SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 2,
-			 2,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 1,
-			 1,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD28K_ST2082_Dual_12G,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 2,
-			 2,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD28K_ST2082_RGB_Dual_12G,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 2,
-			 2,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD28K_ST2082_Quad_12G,
-		 {
-			 NTV2_MODE_CAPTURE,
-			 4,
-			 4,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-};

+ 0 - 469
plugins/aja/routing/sdi_rgb_display.h

@@ -1,469 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<SDIWireFormat, RoutingConfig>
-	kSDIRGBDisplayConfigs = {
-		{
-			SDIWireFormat::SD_ST352,
-			{
-				NTV2_MODE_DISPLAY,
-				1,     // num wires
-				1,     // num framestores
-				false, // enable 3G output?
-				false, // enable 6G output?
-				false, // enable 12G output?
-				false, // convert 3Gb -> 3Ga input?
-				false, // convert 3Ga -> 3Gb output?
-				false, // convert RGB 3Ga output?
-				false, // enable 3Gb output?
-				false, // enable 4K Square Division?
-				false, // enable 8K Square Division?
-				false, // enable two-sample-interleave?
-				"",    // RGB Output Route
-			},
-		},
-		{SDIWireFormat::HD_720p_ST292,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 1,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}[0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];",
-		 }},
-		{SDIWireFormat::HD_1080_ST292,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 1,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}[0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];",
-		 }},
-		{SDIWireFormat::HD_1080_ST372_Dual,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 2,
-			 1,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Playout
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}[0];"
-			 "dlo[{ch1}][1]->sdi[{ch2}][0];",
-		 }},
-		{SDIWireFormat::HD_720p_ST425_3Ga,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 1,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Output
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_3Ga,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 1,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Output
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_3Gb_DL,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 1,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Output
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];",
-		 }},
-		{SDIWireFormat::HD_720p_ST425_3Gb,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Output
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_3Gb,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 // Output
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_Dual_3Ga,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 2,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "",
-		 }},
-		{SDIWireFormat::HD_1080p_ST425_Dual_3Gb,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 2,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 "",
-		 }},
-		{SDIWireFormat::UHD4K_ST292_Quad_1_5_Squares,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 4,
-			 4,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 // Playout
-			 "fb[{ch1}][0]->sdi[{ch1}][0];"
-			 "fb[{ch2}][0]->sdi[{ch2}][0];"
-			 "fb[{ch3}][0]->sdi[{ch3}][0];"
-			 "fb[{ch4}][0]->sdi[{ch4}][0];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Ga_Squares,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 // Playout
-			 "fb[{ch1}][0]->sdi[{ch1}][0];"
-			 "fb[{ch2}][0]->sdi[{ch2}][0];"
-			 "fb[{ch3}][0]->sdi[{ch3}][0];"
-			 "fb[{ch4}][0]->sdi[{ch4}][0];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Gb_Squares,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 // Framestores 1-4 -> Dual-Link 1-4 -> SDI 1-4
-			 "fb[{ch1}][2]->dlo[{ch1}][0];"
-			 "fb[{ch2}][2]->dlo[{ch2}][0];"
-			 "fb[{ch3}][2]->dlo[{ch3}][0];"
-			 "fb[{ch4}][2]->dlo[{ch4}][0];"
-
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];"
-
-			 "dlo[{ch2}][0]->sdi[{ch2}][0];"
-			 "dlo[{ch2}][1]->sdi[{ch2}][1];"
-
-			 "dlo[{ch3}][0]->sdi[{ch3}][0];"
-			 "dlo[{ch3}][1]->sdi[{ch3}][1];"
-
-			 "dlo[{ch4}][0]->sdi[{ch4}][0];"
-			 "dlo[{ch4}][1]->sdi[{ch4}][1];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Dual_3Gb_2SI,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 2,
-			 2,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Ga_2SI,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 // Framestores 1-2 -> TSI Mux 1-2
-			 // -> Dual-Link 1-4 -> SDI 1-4
-			 "fb[{ch1}][2]->tsi[{ch1}][0];"
-			 "fb[{ch1}][3]->tsi[{ch1}][1];"
-
-			 "fb[{ch2}][2]->tsi[{ch2}][0];"
-			 "fb[{ch2}][3]->tsi[{ch2}][1];"
-
-			 "tsi[{ch1}][2]->dlo[{ch1}][0];"
-			 "tsi[{ch1}][3]->dlo[{ch2}][0];"
-			 "tsi[{ch2}][2]->dlo[{ch3}][0];"
-			 "tsi[{ch2}][3]->dlo[{ch4}][0];"
-
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];"
-			 "dlo[{ch2}][0]->sdi[{ch2}][0];"
-			 "dlo[{ch2}][1]->sdi[{ch2}][1];"
-			 "dlo[{ch3}][0]->sdi[{ch3}][0];"
-			 "dlo[{ch3}][1]->sdi[{ch3}][1];"
-			 "dlo[{ch4}][0]->sdi[{ch4}][0];"
-			 "dlo[{ch4}][1]->sdi[{ch4}][1];",
-		 }},
-		{SDIWireFormat::UHD4K_ST425_Quad_3Gb_2SI,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 4,
-			 4,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 // Framestores 1-2 -> TSI Mux 1-2
-			 // -> Dual-Link 1-4 -> SDI 1-4
-			 "fb[{ch1}][2]->tsi[{ch1}][0];"
-			 "fb[{ch1}][3]->tsi[{ch1}][1];"
-
-			 "fb[{ch2}][2]->tsi[{ch2}][0];"
-			 "fb[{ch2}][3]->tsi[{ch2}][1];"
-
-			 "tsi[{ch1}][2]->dlo[{ch1}][0];"
-			 "tsi[{ch1}][3]->dlo[{ch2}][0];"
-			 "tsi[{ch2}][2]->dlo[{ch3}][0];"
-			 "tsi[{ch2}][3]->dlo[{ch4}][0];"
-
-			 "dlo[{ch1}][0]->sdi[{ch1}][0];"
-			 "dlo[{ch1}][1]->sdi[{ch1}][1];"
-			 "dlo[{ch2}][0]->sdi[{ch2}][0];"
-			 "dlo[{ch2}][1]->sdi[{ch2}][1];"
-			 "dlo[{ch3}][0]->sdi[{ch3}][0];"
-			 "dlo[{ch3}][1]->sdi[{ch3}][1];"
-			 "dlo[{ch4}][0]->sdi[{ch4}][0];"
-			 "dlo[{ch4}][1]->sdi[{ch4}][1];",
-		 }},
-		{SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 2,
-			 2,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 1,
-			 1,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD28K_ST2082_Dual_12G,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 2,
-			 2,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD28K_ST2082_RGB_Dual_12G,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 2,
-			 2,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-		{SDIWireFormat::UHD28K_ST2082_Quad_12G,
-		 {
-			 NTV2_MODE_DISPLAY,
-			 4,
-			 4,
-			 false,
-			 false,
-			 true,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 false,
-			 true,
-			 "",
-		 }},
-};

+ 0 - 466
plugins/aja/routing/sdi_ycbcr_capture.h

@@ -1,466 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<SDIWireFormat, RoutingConfig> kSDIYCbCrCaptureConfigs = {
-	{
-		SDIWireFormat::SD_ST352,
-		{
-			NTV2_MODE_CAPTURE,
-			1,     // num wires
-			1,     // num framestores
-			false, // enable 3G output?
-			false, // enable 6G output?
-			false, // enable 12G output?
-			false, // convert 3Gb -> 3Ga input?
-			false, // convert 3Ga -> 3Gb output?
-			false, // convert RGB 3Ga output?
-			false, // enable 3Gb output?
-			false, // enable 4K Square Division?
-			false, // enable 8K Square Division?
-			false, // enable two-sample-interleave?
-			"sdi[{ch1}][0]->fb[{ch1}][0]", // YCbCr Capture Route
-		},
-	},
-	{SDIWireFormat::HD_720p_ST292,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080_ST292,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080_ST372_Dual,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 2,
-		 2,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]; sdi[{ch2}][0]->fb[{ch2}][0]",
-	 }},
-	{SDIWireFormat::HD_720p_ST425_3Ga,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_3Ga,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_3Gb_DL,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 true,
-		 false,
-		 false,
-		 true,
-		 true,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_720p_ST425_3Gb,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 2,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]; sdi[{ch1}][1]->fb[{ch2}][0];",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_3Gb,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 2,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0]; sdi[{ch1}][1]->fb[{ch2}][0];",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_Dual_3Ga,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 2,
-		 2,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0];"
-		 "sdi[{ch2}][0]->fb[{ch2}][0];",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_Dual_3Gb,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 2,
-		 2,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0];"
-		 "sdi[{ch2}][0]->fb[{ch2}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST292_Dual_1_5_Squares,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 2,
-		 4,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 "sdi[{ch1}][0]->fb[{ch1}][0];"
-		 "sdi[{ch1}][1]->fb[{ch2}][0];"
-		 "sdi[{ch2}][0]->fb[{ch3}][0];"
-		 "sdi[{ch2}][1]->fb[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST292_Quad_1_5_Squares,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 4,
-		 4,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 // Capture
-		 "sdi[{ch1}][0]->fb[{ch1}][0];"
-		 "sdi[{ch2}][0]->fb[{ch2}][0];"
-		 "sdi[{ch3}][0]->fb[{ch3}][0];"
-		 "sdi[{ch4}][0]->fb[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Ga_Squares,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 4,
-		 4,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 // Capture
-		 "sdi[{ch1}][0]->fb[{ch1}][0];"
-		 "sdi[{ch2}][0]->fb[{ch2}][0];"
-		 "sdi[{ch3}][0]->fb[{ch3}][0];"
-		 "sdi[{ch4}][0]->fb[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Gb_Squares,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 4,
-		 4,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 // Capture
-		 "sdi[{ch1}][0]->fb[{ch1}][0];"
-		 "sdi[{ch2}][0]->fb[{ch2}][0];"
-		 "sdi[{ch3}][0]->fb[{ch3}][0];"
-		 "sdi[{ch4}][0]->fb[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Dual_3Gb_2SI,
-	 {NTV2_MODE_CAPTURE, 2, 2, true, false, false, false, false, false,
-	  false, false, false, true,
-	  "sdi[{ch1}][0]->tsi[{ch1}][0];"
-	  "sdi[{ch1}][1]->tsi[{ch1}][1];"
-	  "sdi[{ch2}][0]->tsi[{ch2}][0];"
-	  "sdi[{ch2}][1]->tsi[{ch2}][1];"
-	  "tsi[{ch1}][0]->fb[{ch1}][0];"
-	  "tsi[{ch1}][1]->fb[{ch1}][1];"
-	  "tsi[{ch2}][0]->fb[{ch2}][0];"
-	  "tsi[{ch2}][1]->fb[{ch2}][1];"}},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Ga_2SI,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 4,
-		 4,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "sdi[{ch1}][0]->tsi[{ch1}][0];"
-		 "sdi[{ch2}][0]->tsi[{ch1}][1];"
-		 "sdi[{ch3}][0]->tsi[{ch2}][0];"
-		 "sdi[{ch4}][0]->tsi[{ch2}][1];"
-		 "tsi[{ch1}][0]->fb[{ch1}][0];"
-		 "tsi[{ch1}][1]->fb[{ch1}][1];"
-		 "tsi[{ch2}][0]->fb[{ch2}][0];"
-		 "tsi[{ch2}][1]->fb[{ch2}][1];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Gb_2SI,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 4,
-		 4,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "sdi[{ch1}][0]->tsi[{ch1}][0];"
-		 "sdi[{ch2}][0]->tsi[{ch1}][1];"
-		 "sdi[{ch3}][0]->tsi[{ch2}][0];"
-		 "sdi[{ch4}][0]->tsi[{ch2}][1];"
-		 "tsi[{ch1}][0]->fb[{ch1}][0];"
-		 "tsi[{ch1}][1]->fb[{ch1}][1];"
-		 "tsi[{ch2}][0]->fb[{ch2}][0];"
-		 "tsi[{ch2}][1]->fb[{ch2}][1];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "sdi[{ch1}][0]->fb[{ch1}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI_Kona5_io4KPlus,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 2,
-		 2,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 // Capture
-		 "sdi[{ch1}][0]->tsi[{ch1}][0];"
-		 "sdi[{ch2}][0]->tsi[{ch1}][1];"
-		 "sdi[{ch3}][0]->tsi[{ch2}][0];"
-		 "sdi[{ch4}][0]->tsi[{ch2}][1];"
-		 "tsi[{ch1}][0]->fb[{ch1}][0];"
-		 "tsi[{ch1}][1]->fb[{ch1}][1];"
-		 "tsi[{ch2}][0]->fb[{ch2}][0];"
-		 "tsi[{ch2}][1]->fb[{ch2}][1];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "sdi[{ch1}][0]->fb[{ch1}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI_Kona5_io4KPlus,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 1,
-		 1,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "",
-	 }},
-	{SDIWireFormat::UHD28K_ST2082_Dual_12G,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 2,
-		 2,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "",
-	 }},
-	{SDIWireFormat::UHD28K_ST2082_RGB_Dual_12G,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 2,
-		 2,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "",
-	 }},
-	{SDIWireFormat::UHD28K_ST2082_Quad_12G,
-	 {
-		 NTV2_MODE_CAPTURE,
-		 4,
-		 4,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "",
-	 }},
-};

+ 0 - 486
plugins/aja/routing/sdi_ycbcr_display.h

@@ -1,486 +0,0 @@
-#pragma once
-
-#include "../aja-routing.hpp"
-
-static inline const std::map<SDIWireFormat, RoutingConfig> kSDIYCbCrDisplayConfigs = {
-	{
-		SDIWireFormat::SD_ST352,
-		{
-			NTV2_MODE_DISPLAY,
-			1,     // num wires
-			1,     // num framestores
-			false, // enable 3G output?
-			false, // enable 6G output?
-			false, // enable 12G output?
-			false, // convert 3Gb -> 3Ga input?
-			false, // convert 3Ga -> 3Gb output?
-			false, // convert RGB 3Ga output?
-			false, // enable 3Gb output?
-			false, // enable 4K Square Division?
-			false, // enable 8K Square Division?
-			false, // enable two-sample-interleave?
-			"fb[{ch1}][0]->sdi[{ch1}][0]", // YCbCr Output Route
-		},
-	},
-	{SDIWireFormat::HD_720p_ST292,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080_ST292,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080_ST372_Dual,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 2,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0];"
-		 "fb[{ch2}][0]->sdi[{ch2}][0]",
-	 }},
-	{SDIWireFormat::HD_720p_ST425_3Ga,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_3Ga,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_3Gb_DL,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 true,
-		 false,
-		 false,
-		 true,
-		 true,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0]",
-	 }},
-	{SDIWireFormat::HD_720p_ST425_3Gb,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 2,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0]; fb[{ch2}][0]->sdi[{ch1}][1];",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_3Gb,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 2,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0]; fb[{ch2}][0]->sdi[{ch1}][1];",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_Dual_3Ga,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 2,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "",
-	 }},
-	{SDIWireFormat::HD_1080p_ST425_Dual_3Gb,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 2,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 "",
-	 }},
-	{SDIWireFormat::UHD4K_ST292_Dual_1_5_Squares,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 4,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 "fb[{ch1}][0]->sdi[{ch1}][0];"
-		 "fb[{ch2}][0]->sdi[{ch1}][1];"
-		 "fb[{ch3}][0]->sdi[{ch2}][0];"
-		 "fb[{ch4}][0]->sdi[{ch2}][1];",
-	 }},
-	{SDIWireFormat::UHD4K_ST292_Quad_1_5_Squares,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 4,
-		 4,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 // Playout
-		 "fb[{ch1}][0]->sdi[{ch1}][0];"
-		 "fb[{ch2}][0]->sdi[{ch2}][0];"
-		 "fb[{ch3}][0]->sdi[{ch3}][0];"
-		 "fb[{ch4}][0]->sdi[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Ga_Squares,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 4,
-		 4,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 // Playout
-		 "fb[{ch1}][0]->sdi[{ch1}][0];"
-		 "fb[{ch2}][0]->sdi[{ch2}][0];"
-		 "fb[{ch3}][0]->sdi[{ch3}][0];"
-		 "fb[{ch4}][0]->sdi[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Gb_Squares,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 4,
-		 4,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 // Playout
-		 "fb[{ch1}][0]->sdi[{ch1}][0];"
-		 "fb[{ch2}][0]->sdi[{ch2}][0];"
-		 "fb[{ch3}][0]->sdi[{ch3}][0];"
-		 "fb[{ch4}][0]->sdi[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Dual_3Gb_2SI,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 2,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 true,
-		 "fb[{ch1}][0]->tsi[{ch1}][0];"
-		 "fb[{ch1}][1]->tsi[{ch1}][1];"
-		 "fb[{ch2}][0]->tsi[{ch2}][0];"
-		 "fb[{ch2}][1]->tsi[{ch2}][1];"
-		 "tsi[{ch1}][0]->sdi[{ch1}][0];"
-		 "tsi[{ch1}][1]->sdi[{ch1}][1];"
-		 "tsi[{ch2}][0]->sdi[{ch2}][0];"
-		 "tsi[{ch2}][1]->sdi[{ch2}][1];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Ga_2SI,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 4,
-		 4,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "fb[{ch1}][0]->tsi[{ch1}][0];"
-		 "fb[{ch1}][1]->tsi[{ch1}][1];"
-		 "fb[{ch2}][0]->tsi[{ch2}][0];"
-		 "fb[{ch2}][1]->tsi[{ch2}][1];"
-		 "tsi[{ch1}][0]->sdi[{ch1}][0];"
-		 "tsi[{ch1}][1]->sdi[{ch2}][0];"
-		 "tsi[{ch2}][0]->sdi[{ch3}][0];"
-		 "tsi[{ch2}][1]->sdi[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST425_Quad_3Gb_2SI,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 4,
-		 4,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 true,
-		 "fb[{ch1}][0]->tsi[{ch1}][0];"
-		 "fb[{ch1}][1]->tsi[{ch1}][1];"
-		 "fb[{ch2}][0]->tsi[{ch2}][0];"
-		 "fb[{ch2}][1]->tsi[{ch2}][1];"
-		 "tsi[{ch1}][0]->sdi[{ch1}][0];"
-		 "tsi[{ch1}][1]->sdi[{ch2}][0];"
-		 "tsi[{ch2}][0]->sdi[{ch3}][0];"
-		 "tsi[{ch2}][1]->sdi[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "fb[{ch1}][0]->sdi[{ch1}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_6G_Squares_2SI_Kona5_io4KPlus,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 2,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 // Playout
-		 "fb[{ch3}][0]->tsi[{ch3}][0];"
-		 "fb[{ch3}][1]->tsi[{ch3}][1];"
-		 "fb[{ch4}][0]->tsi[{ch4}][0];"
-		 "fb[{ch4}][1]->tsi[{ch4}][1];"
-		 "tsi[{ch3}][0]->sdi[{ch1}][0];"
-		 "tsi[{ch3}][1]->sdi[{ch2}][0];"
-		 "tsi[{ch4}][0]->sdi[{ch3}][0];"
-		 "tsi[{ch4}][1]->sdi[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "fb[{ch1}][0]->sdi[{ch1}][0];",
-	 }},
-	{SDIWireFormat::UHD4K_ST2018_12G_Squares_2SI_Kona5_io4KPlus,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 1,
-		 1,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 true,
-		 // Playout
-		 "fb[{ch3}][0]->tsi[{ch3}][0];"
-		 "fb[{ch3}][1]->tsi[{ch3}][1];"
-		 "fb[{ch4}][0]->tsi[{ch4}][0];"
-		 "fb[{ch4}][1]->tsi[{ch4}][1];"
-		 "tsi[{ch3}][0]->sdi[{ch1}][0];"
-		 "tsi[{ch3}][1]->sdi[{ch2}][0];"
-		 "tsi[{ch4}][0]->sdi[{ch3}][0];"
-		 "tsi[{ch4}][1]->sdi[{ch4}][0];",
-	 }},
-	{SDIWireFormat::UHD28K_ST2082_Dual_12G,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 2,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "",
-	 }},
-	{SDIWireFormat::UHD28K_ST2082_RGB_Dual_12G,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 2,
-		 2,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "",
-	 }},
-	{SDIWireFormat::UHD28K_ST2082_Quad_12G,
-	 {
-		 NTV2_MODE_DISPLAY,
-		 4,
-		 4,
-		 false,
-		 false,
-		 true,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 false,
-		 true,
-		 "",
-	 }},
-};