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

This commit is contained in:
Paul Hindt
2022-01-07 18:45:08 -08:00
committed by Colin Edwards
parent d78971b4db
commit f09137a2e0
32 changed files with 2806 additions and 3297 deletions

View File

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