mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-05-06 06:14:43 -04:00
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:
committed by
Colin Edwards
parent
d78971b4db
commit
f09137a2e0
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user