aja-common.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. #include "aja-card-manager.hpp"
  2. #include "aja-common.hpp"
  3. #include "aja-ui-props.hpp"
  4. #include "aja-props.hpp"
  5. #include <ajantv2/includes/ntv2debug.h>
  6. #include <ajantv2/includes/ntv2devicescanner.h>
  7. #include <ajantv2/includes/ntv2devicefeatures.h>
  8. #include <ajantv2/includes/ntv2signalrouter.h>
  9. #include <ajantv2/includes/ntv2utils.h>
  10. void filter_io_selection_input_list(const std::string &cardID, const std::string &channelOwner, obs_property_t *list)
  11. {
  12. auto &cardManager = aja::CardManager::Instance();
  13. auto cardEntry = cardManager.GetCardEntry(cardID);
  14. if (!cardEntry) {
  15. blog(LOG_DEBUG, "filter_io_selection_input_list: Card Entry not found for %s", cardID.c_str());
  16. return;
  17. }
  18. NTV2DeviceID deviceID = DEVICE_ID_NOTFOUND;
  19. CNTV2Card *card = cardEntry->GetCard();
  20. if (card)
  21. deviceID = card->GetDeviceID();
  22. // Gray out the IOSelection list items that are in use by other plugin instances
  23. for (size_t idx = 0; idx < obs_property_list_item_count(list); idx++) {
  24. auto io_select = static_cast<IOSelection>(obs_property_list_item_int(list, idx));
  25. if (io_select == IOSelection::Invalid) {
  26. obs_property_list_item_disable(list, idx, false);
  27. continue;
  28. }
  29. bool enabled = cardEntry->InputSelectionReady(io_select, deviceID, channelOwner);
  30. obs_property_list_item_disable(list, idx, !enabled);
  31. blog(LOG_DEBUG, "IOSelection %s = %s", aja::IOSelectionToString(io_select).c_str(),
  32. enabled ? "enabled" : "disabled");
  33. }
  34. }
  35. void filter_io_selection_output_list(const std::string &cardID, const std::string &channelOwner, obs_property_t *list)
  36. {
  37. auto &cardManager = aja::CardManager::Instance();
  38. auto cardEntry = cardManager.GetCardEntry(cardID);
  39. if (!cardEntry) {
  40. blog(LOG_DEBUG, "filter_io_selection_output_list: Card Entry not found for %s", cardID.c_str());
  41. return;
  42. }
  43. NTV2DeviceID deviceID = DEVICE_ID_NOTFOUND;
  44. CNTV2Card *card = cardEntry->GetCard();
  45. if (card)
  46. deviceID = card->GetDeviceID();
  47. // Gray out the IOSelection list items that are in use by other plugin instances
  48. for (size_t idx = 0; idx < obs_property_list_item_count(list); idx++) {
  49. auto io_select = static_cast<IOSelection>(obs_property_list_item_int(list, idx));
  50. if (io_select == IOSelection::Invalid) {
  51. obs_property_list_item_disable(list, idx, false);
  52. continue;
  53. }
  54. bool enabled = cardEntry->OutputSelectionReady(io_select, deviceID, channelOwner);
  55. obs_property_list_item_disable(list, idx, !enabled);
  56. blog(LOG_DEBUG, "IOSelection %s = %s", aja::IOSelectionToString(io_select).c_str(),
  57. enabled ? "enabled" : "disabled");
  58. }
  59. }
  60. void populate_io_selection_input_list(const std::string &cardID, const std::string &channelOwner, NTV2DeviceID deviceID,
  61. obs_property_t *list)
  62. {
  63. obs_property_list_clear(list);
  64. obs_property_list_add_int(list, obs_module_text(kUIPropIOSelectNone.text),
  65. static_cast<long long>(IOSelection::Invalid));
  66. for (auto i = 0; i < static_cast<int32_t>(IOSelection::NumIOSelections); i++) {
  67. auto ioSelect = static_cast<IOSelection>(i);
  68. if (ioSelect == IOSelection::AnalogIn)
  69. continue;
  70. if (aja::DeviceCanDoIOSelectionIn(deviceID, ioSelect)) {
  71. obs_property_list_add_int(list, aja::IOSelectionToString(ioSelect).c_str(),
  72. static_cast<long long>(ioSelect));
  73. }
  74. }
  75. filter_io_selection_input_list(cardID, channelOwner, list);
  76. }
  77. void populate_io_selection_output_list(const std::string &cardID, const std::string &channelOwner,
  78. NTV2DeviceID deviceID, obs_property_t *list)
  79. {
  80. obs_property_list_clear(list);
  81. obs_property_list_add_int(list, obs_module_text(kUIPropIOSelectNone.text),
  82. static_cast<long long>(IOSelection::Invalid));
  83. if (deviceID == DEVICE_ID_TTAP_PRO) {
  84. obs_property_list_add_int(list, "SDI & HDMI", static_cast<long long>(IOSelection::HDMIMonitorOut));
  85. } else {
  86. for (auto i = 0; i < static_cast<int32_t>(IOSelection::NumIOSelections); i++) {
  87. auto ioSelect = static_cast<IOSelection>(i);
  88. if (ioSelect == IOSelection::Invalid || ioSelect == IOSelection::AnalogOut)
  89. continue;
  90. if (aja::DeviceCanDoIOSelectionOut(deviceID, ioSelect)) {
  91. obs_property_list_add_int(list, aja::IOSelectionToString(ioSelect).c_str(),
  92. static_cast<long long>(ioSelect));
  93. }
  94. }
  95. }
  96. filter_io_selection_output_list(cardID, channelOwner, list);
  97. }
  98. void populate_video_format_list(NTV2DeviceID deviceID, obs_property_t *list, NTV2VideoFormat genlockFormat,
  99. bool want4KHFR, bool matchFPS)
  100. {
  101. VideoFormatList videoFormats = {};
  102. VideoStandardList orderedStandards = {};
  103. orderedStandards.push_back(NTV2_STANDARD_525);
  104. orderedStandards.push_back(NTV2_STANDARD_625);
  105. if (NTV2DeviceCanDoHDVideo(deviceID)) {
  106. orderedStandards.push_back(NTV2_STANDARD_720);
  107. orderedStandards.push_back(NTV2_STANDARD_1080);
  108. orderedStandards.push_back(NTV2_STANDARD_1080p);
  109. orderedStandards.push_back(NTV2_STANDARD_2K);
  110. orderedStandards.push_back(NTV2_STANDARD_2Kx1080p);
  111. orderedStandards.push_back(NTV2_STANDARD_2Kx1080i);
  112. }
  113. if (NTV2DeviceCanDo4KVideo(deviceID)) {
  114. orderedStandards.push_back(NTV2_STANDARD_3840i);
  115. orderedStandards.push_back(NTV2_STANDARD_3840x2160p);
  116. if (want4KHFR)
  117. orderedStandards.push_back(NTV2_STANDARD_3840HFR);
  118. orderedStandards.push_back(NTV2_STANDARD_4096i);
  119. orderedStandards.push_back(NTV2_STANDARD_4096x2160p);
  120. if (want4KHFR)
  121. orderedStandards.push_back(NTV2_STANDARD_4096HFR);
  122. }
  123. aja::GetSortedVideoFormats(deviceID, orderedStandards, videoFormats);
  124. for (const auto &vf : videoFormats) {
  125. bool addFormat = true;
  126. // Filter formats by framerate family if specified
  127. if (genlockFormat != NTV2_FORMAT_UNKNOWN)
  128. addFormat = IsMultiFormatCompatible(genlockFormat, vf);
  129. struct obs_video_info ovi;
  130. if (matchFPS && obs_get_video_info(&ovi)) {
  131. NTV2FrameRate frameRate = GetNTV2FrameRateFromVideoFormat(vf);
  132. ULWord fpsNum = 0;
  133. ULWord fpsDen = 0;
  134. GetFramesPerSecond(frameRate, fpsNum, fpsDen);
  135. uint32_t obsFrameTime = 1000000 * ovi.fps_den / ovi.fps_num;
  136. uint32_t ajaFrameTime = 1000000 * fpsDen / fpsNum;
  137. if (obsFrameTime != ajaFrameTime)
  138. addFormat = false;
  139. }
  140. if (addFormat) {
  141. std::string name = NTV2VideoFormatToString(vf, true);
  142. obs_property_list_add_int(list, name.c_str(), (int)vf);
  143. }
  144. }
  145. }
  146. void populate_pixel_format_list(NTV2DeviceID deviceID, const std::vector<NTV2PixelFormat> &fmts, obs_property_t *list)
  147. {
  148. for (auto &&pf : fmts) {
  149. if (NTV2DeviceCanDoFrameBufferFormat(deviceID, pf)) {
  150. obs_property_list_add_int(list, NTV2FrameBufferFormatToString(pf, true).c_str(),
  151. static_cast<long long>(pf));
  152. }
  153. }
  154. }
  155. void populate_sdi_transport_list(obs_property_t *list, NTV2DeviceID deviceID, bool capture)
  156. {
  157. if (capture) {
  158. obs_property_list_add_int(list, obs_module_text("Auto"), kAutoDetect);
  159. }
  160. for (int i = 0; i < (int)SDITransport::Unknown; i++) {
  161. SDITransport sdi_trx = static_cast<SDITransport>(i);
  162. if (sdi_trx == SDITransport::SDI6G || sdi_trx == SDITransport::SDI12G) {
  163. if (!NTV2DeviceCanDo12GSDI(deviceID))
  164. continue;
  165. }
  166. // Disabling 12G in Output plugin until AJA 4K HFR bug is fixed
  167. if (!capture && sdi_trx == SDITransport::SDI12G)
  168. continue;
  169. obs_property_list_add_int(list, aja::SDITransportToString(sdi_trx).c_str(),
  170. static_cast<long long>(sdi_trx));
  171. }
  172. }
  173. void populate_sdi_4k_transport_list(obs_property_t *list)
  174. {
  175. obs_property_list_add_int(list, aja::SDITransport4KToString(SDITransport4K::Squares).c_str(),
  176. static_cast<long long>(SDITransport4K::Squares));
  177. obs_property_list_add_int(list, aja::SDITransport4KToString(SDITransport4K::TwoSampleInterleave).c_str(),
  178. static_cast<long long>(SDITransport4K::TwoSampleInterleave));
  179. }
  180. bool aja_video_format_changed(obs_properties_t *props, obs_property_t *list, obs_data_t *settings)
  181. {
  182. auto vid_fmt = static_cast<NTV2VideoFormat>(obs_data_get_int(settings, kUIPropVideoFormatSelect.id));
  183. size_t itemCount = obs_property_list_item_count(list);
  184. bool itemFound = false;
  185. for (size_t i = 0; i < itemCount; i++) {
  186. auto itemFormat = static_cast<NTV2VideoFormat>(obs_property_list_item_int(list, i));
  187. if (itemFormat == vid_fmt) {
  188. itemFound = true;
  189. break;
  190. }
  191. }
  192. if (!itemFound) {
  193. obs_property_list_insert_int(list, 0, "", vid_fmt);
  194. obs_property_list_item_disable(list, 0, true);
  195. return true;
  196. }
  197. obs_property_t *sdi_4k_trx = obs_properties_get(props, kUIPropSDITransport4K.id);
  198. obs_property_set_visible(sdi_4k_trx, NTV2_IS_4K_VIDEO_FORMAT(vid_fmt));
  199. return true;
  200. }
  201. namespace aja {
  202. video_format AJAPixelFormatToOBSVideoFormat(NTV2PixelFormat pf)
  203. {
  204. video_format obs_video_format = VIDEO_FORMAT_NONE;
  205. switch (pf) {
  206. case NTV2_FBF_8BIT_YCBCR:
  207. obs_video_format = VIDEO_FORMAT_UYVY;
  208. break;
  209. case NTV2_FBF_24BIT_RGB:
  210. case NTV2_FBF_24BIT_BGR:
  211. obs_video_format = VIDEO_FORMAT_BGR3;
  212. break;
  213. case NTV2_FBF_ARGB:
  214. case NTV2_FBF_ABGR:
  215. case NTV2_FBF_RGBA:
  216. obs_video_format = VIDEO_FORMAT_BGRA;
  217. break;
  218. case NTV2_FBF_10BIT_YCBCR:
  219. obs_video_format = VIDEO_FORMAT_V210;
  220. break;
  221. case NTV2_FBF_10BIT_RGB:
  222. case NTV2_FBF_8BIT_YCBCR_YUY2:
  223. case NTV2_FBF_10BIT_DPX:
  224. case NTV2_FBF_10BIT_YCBCR_DPX:
  225. case NTV2_FBF_8BIT_DVCPRO:
  226. case NTV2_FBF_8BIT_YCBCR_420PL3:
  227. case NTV2_FBF_8BIT_HDV:
  228. case NTV2_FBF_10BIT_YCBCRA:
  229. case NTV2_FBF_10BIT_DPX_LE:
  230. case NTV2_FBF_48BIT_RGB:
  231. case NTV2_FBF_12BIT_RGB_PACKED:
  232. case NTV2_FBF_PRORES_DVCPRO:
  233. case NTV2_FBF_PRORES_HDV:
  234. case NTV2_FBF_10BIT_RGB_PACKED:
  235. case NTV2_FBF_10BIT_ARGB:
  236. case NTV2_FBF_16BIT_ARGB:
  237. case NTV2_FBF_8BIT_YCBCR_422PL3:
  238. case NTV2_FBF_10BIT_RAW_RGB:
  239. case NTV2_FBF_10BIT_RAW_YCBCR:
  240. case NTV2_FBF_10BIT_YCBCR_420PL3_LE:
  241. case NTV2_FBF_10BIT_YCBCR_422PL3_LE:
  242. case NTV2_FBF_10BIT_YCBCR_420PL2:
  243. case NTV2_FBF_10BIT_YCBCR_422PL2:
  244. case NTV2_FBF_8BIT_YCBCR_420PL2:
  245. case NTV2_FBF_8BIT_YCBCR_422PL2:
  246. default:
  247. obs_video_format = VIDEO_FORMAT_NONE;
  248. break;
  249. }
  250. return obs_video_format;
  251. }
  252. void GetSortedVideoFormats(NTV2DeviceID id, const VideoStandardList &standards, VideoFormatList &videoFormats)
  253. {
  254. if (standards.empty())
  255. return;
  256. VideoFormatMap videoFormatMap;
  257. // Bin all the formats based on video standard
  258. for (size_t i = (size_t)NTV2_FORMAT_UNKNOWN; i < (size_t)NTV2_MAX_NUM_VIDEO_FORMATS; i++) {
  259. NTV2VideoFormat fmt = (NTV2VideoFormat)i;
  260. NTV2Standard standard = GetNTV2StandardFromVideoFormat(fmt);
  261. if (id != DEVICE_ID_NOTFOUND && NTV2DeviceCanDoVideoFormat(id, fmt)) {
  262. if (videoFormatMap.count(standard)) {
  263. videoFormatMap.at(standard).push_back(fmt);
  264. } else {
  265. std::vector<NTV2VideoFormat> v;
  266. v.push_back(fmt);
  267. videoFormatMap.insert(
  268. std::pair<NTV2Standard, std::vector<NTV2VideoFormat>>(standard, v));
  269. }
  270. }
  271. }
  272. for (size_t v = (size_t)NTV2_STANDARD_1080; v < (size_t)NTV2_NUM_STANDARDS; v++) {
  273. NTV2Standard standard = (NTV2Standard)v;
  274. if (videoFormatMap.count(standard)) {
  275. std::sort(videoFormatMap.at(standard).begin(), videoFormatMap.at(standard).end(),
  276. [&](const NTV2VideoFormat &d1, const NTV2VideoFormat &d2) {
  277. std::string d1Str, d2Str;
  278. d1Str = NTV2VideoFormatToString(d1);
  279. d2Str = NTV2VideoFormatToString(d2);
  280. return d1Str < d2Str;
  281. });
  282. }
  283. }
  284. for (size_t v = 0; v < standards.size(); v++) {
  285. NTV2Standard standard = standards.at(v);
  286. if (videoFormatMap.count(standard)) {
  287. for (size_t i = 0; i < videoFormatMap.at(standard).size(); i++) {
  288. NTV2VideoFormat vf = videoFormatMap.at(standard).at(i);
  289. videoFormats.push_back(vf);
  290. }
  291. }
  292. }
  293. }
  294. NTV2VideoFormat HandleSpecialCaseFormats(IOSelection io, NTV2VideoFormat vf, NTV2DeviceID id)
  295. {
  296. // 1080p Level-B formats and ST372M
  297. if (NTV2_VIDEO_FORMAT_IS_B(vf) && !(IsSDITwoWireIOSelection(io) && NTV2_IS_HD_VIDEO_FORMAT(vf))) {
  298. vf = aja::GetLevelAFormatForLevelBFormat(vf);
  299. }
  300. // UHD/4K Square Division auto-detect
  301. if ((io == IOSelection::SDI1__4 || io == IOSelection::SDI5__8) && NTV2_IS_HD_VIDEO_FORMAT(vf)) {
  302. vf = GetQuadSizedVideoFormat(vf, true);
  303. }
  304. // Kona5/io4K+ auto-detection of UHD/4K 6G/12G SDI formats.
  305. if (aja::IsSDIOneWireIOSelection(io) && NTV2_IS_4K_VIDEO_FORMAT(vf) && !NTV2_IS_SQUARE_DIVISION_FORMAT(vf) &&
  306. !NTV2DeviceCanDo12gRouting(id)) {
  307. vf = GetQuadSizedVideoFormat(GetQuarterSizedVideoFormat(vf));
  308. }
  309. return vf;
  310. }
  311. NTV2Channel WidgetIDToChannel(NTV2WidgetID id)
  312. {
  313. #if AJA_NTV2_SDK_VERSION_MAJOR <= 16 && AJA_NTV2_SDK_VERSION_MINOR <= 2
  314. // Workaround for bug in NTV2 SDK <= 16.2 where NTV2_WgtSDIMonOut1 maps incorrectly to NTV2_CHANNEL1.
  315. if (id == NTV2_WgtSDIMonOut1)
  316. return NTV2_CHANNEL5;
  317. #endif
  318. return CNTV2SignalRouter::WidgetIDToChannel(id);
  319. }
  320. uint32_t CardNumFramestores(NTV2DeviceID id)
  321. {
  322. auto numFramestores = NTV2DeviceGetNumFrameStores(id);
  323. if (id == DEVICE_ID_CORVIDHBR) {
  324. numFramestores = 1;
  325. }
  326. return numFramestores;
  327. }
  328. uint32_t CardNumAudioSystems(NTV2DeviceID id)
  329. {
  330. if (id == DEVICE_ID_KONALHI || id == DEVICE_ID_KONALHEPLUS)
  331. return 2;
  332. return NTV2DeviceGetNumAudioSystems(id);
  333. }
  334. // IO4K and IO4K+ perform SDI Monitor Output on "SDI5" and "Framestore 4".
  335. bool CardCanDoSDIMonitorOutput(NTV2DeviceID id)
  336. {
  337. return (id == DEVICE_ID_IO4K || id == DEVICE_ID_IO4KPLUS);
  338. }
  339. // Cards with a dedicated HDMI Monitor Input, tied to "Framestore 4".
  340. bool CardCanDoHDMIMonitorInput(NTV2DeviceID id)
  341. {
  342. return (id == DEVICE_ID_IO4K || id == DEVICE_ID_IO4KUFC || id == DEVICE_ID_IO4KPLUS || id == DEVICE_ID_IOXT ||
  343. id == DEVICE_ID_IOX3 || id == DEVICE_ID_KONALHI);
  344. }
  345. // Cards with a dedicated HDMI Monitor Output, tied to "Framestore 4".
  346. bool CardCanDoHDMIMonitorOutput(NTV2DeviceID id)
  347. {
  348. return (id == DEVICE_ID_IO4K || id == DEVICE_ID_IO4KPLUS || id == DEVICE_ID_IOXT || id == DEVICE_ID_IOX3 ||
  349. id == DEVICE_ID_KONA4 || id == DEVICE_ID_KONA5 || id == DEVICE_ID_KONA5_8K ||
  350. id == DEVICE_ID_KONA5_2X4K || id == DEVICE_ID_KONA5_8KMK);
  351. }
  352. // Cards capable of 1x SDI at 6G/12G.
  353. bool CardCanDo1xSDI12G(NTV2DeviceID id)
  354. {
  355. return (id == DEVICE_ID_KONA5_8K || id == DEVICE_ID_KONA5_8KMK || id == DEVICE_ID_KONA5 ||
  356. id == DEVICE_ID_KONA5_2X4K || id == DEVICE_ID_IO4KPLUS || id == DEVICE_ID_CORVID44_12G);
  357. }
  358. // Check for 3G level-B SDI on the wire.
  359. bool Is3GLevelB(CNTV2Card *card, NTV2Channel channel)
  360. {
  361. if (!card)
  362. return false;
  363. bool levelB = false;
  364. auto deviceID = card->GetDeviceID();
  365. UWord channelIndex = static_cast<UWord>(channel);
  366. if (NTV2DeviceCanDo3GIn(deviceID, channelIndex) || NTV2DeviceCanDo12GIn(deviceID, channelIndex)) {
  367. if (!card->GetSDIInput3GbPresent(levelB, channel))
  368. return false;
  369. }
  370. return levelB;
  371. }
  372. // Get the 3G Level-A enum for a 3G Level-B format enum.
  373. NTV2VideoFormat GetLevelAFormatForLevelBFormat(NTV2VideoFormat vf)
  374. {
  375. NTV2VideoFormat result = vf;
  376. switch (vf) {
  377. default:
  378. break;
  379. case NTV2_FORMAT_1080p_5000_B:
  380. result = NTV2_FORMAT_1080p_5000_A;
  381. break;
  382. case NTV2_FORMAT_1080p_5994_B:
  383. result = NTV2_FORMAT_1080p_5994_A;
  384. break;
  385. case NTV2_FORMAT_1080p_6000_B:
  386. result = NTV2_FORMAT_1080p_6000_A;
  387. break;
  388. case NTV2_FORMAT_1080p_2K_4795_B:
  389. result = NTV2_FORMAT_1080p_2K_4795_A;
  390. break;
  391. case NTV2_FORMAT_1080p_2K_4800_B:
  392. result = NTV2_FORMAT_1080p_2K_4800_A;
  393. break;
  394. case NTV2_FORMAT_1080p_2K_5000_B:
  395. result = NTV2_FORMAT_1080p_2K_5000_A;
  396. break;
  397. case NTV2_FORMAT_1080p_2K_5994_B:
  398. result = NTV2_FORMAT_1080p_2K_5994_A;
  399. break;
  400. case NTV2_FORMAT_1080p_2K_6000_B:
  401. result = NTV2_FORMAT_1080p_2K_6000_A;
  402. break;
  403. }
  404. return result;
  405. }
  406. NTV2VideoFormat InterlacedFormatForPsfFormat(NTV2VideoFormat vf)
  407. {
  408. NTV2VideoFormat result = vf;
  409. switch (vf) {
  410. default:
  411. break;
  412. case NTV2_FORMAT_1080psf_2500_2:
  413. result = NTV2_FORMAT_1080i_5000;
  414. break;
  415. case NTV2_FORMAT_1080psf_2997_2:
  416. result = NTV2_FORMAT_1080i_5994;
  417. break;
  418. }
  419. return result;
  420. }
  421. // Certain cards only have 1 SDI spigot.
  422. bool IsSingleSDIDevice(NTV2DeviceID id)
  423. {
  424. return (id == DEVICE_ID_TTAP_PRO || id == DEVICE_ID_KONA1);
  425. }
  426. bool IsIODevice(NTV2DeviceID id)
  427. {
  428. return (id == DEVICE_ID_IOXT || id == DEVICE_ID_IOX3 || id == DEVICE_ID_IO4K || id == DEVICE_ID_IO4KPLUS ||
  429. id == DEVICE_ID_IOIP_2022 || id == DEVICE_ID_IOIP_2110);
  430. }
  431. /* Kona5 retail firmware and io4K+ have limited support for 6G/12G SDI
  432. * where SDI 1 is capable of capture and SDI 3 is capable of output.
  433. */
  434. bool IsRetail12GSDICard(NTV2DeviceID id)
  435. {
  436. return (id == DEVICE_ID_KONA5 || id == DEVICE_ID_IO4KPLUS);
  437. }
  438. bool IsOutputOnlyDevice(NTV2DeviceID id)
  439. {
  440. return id == DEVICE_ID_TTAP_PRO;
  441. }
  442. std::string SDITransportToString(SDITransport mode)
  443. {
  444. std::string str = "";
  445. switch (mode) {
  446. case SDITransport::SingleLink:
  447. str = "SD/HD Single Link";
  448. break;
  449. case SDITransport::HDDualLink:
  450. str = "HD Dual-Link";
  451. break;
  452. case SDITransport::SDI3Ga:
  453. str = "3G Level-A (3Ga)";
  454. break;
  455. case SDITransport::SDI3Gb:
  456. str = "3G Level-B (3Gb)";
  457. break;
  458. case SDITransport::SDI6G:
  459. str = "6G";
  460. break;
  461. case SDITransport::SDI12G:
  462. str = "12G";
  463. break;
  464. case SDITransport::Unknown:
  465. str = "Unknown";
  466. break;
  467. }
  468. return str;
  469. }
  470. std::string SDITransport4KToString(SDITransport4K mode)
  471. {
  472. std::string str = "";
  473. switch (mode) {
  474. case SDITransport4K::Squares:
  475. str = "Squares";
  476. break;
  477. case SDITransport4K::TwoSampleInterleave:
  478. str = "2SI";
  479. break;
  480. default:
  481. case SDITransport4K::Unknown:
  482. str = "Unknown";
  483. break;
  484. }
  485. return str;
  486. }
  487. std::string IOSelectionToString(IOSelection io)
  488. {
  489. std::string str;
  490. switch (io) {
  491. case IOSelection::SDI1:
  492. str = "SDI 1";
  493. break;
  494. case IOSelection::SDI2:
  495. str = "SDI 2";
  496. break;
  497. case IOSelection::SDI3:
  498. str = "SDI 3";
  499. break;
  500. case IOSelection::SDI4:
  501. str = "SDI 4";
  502. break;
  503. case IOSelection::SDI5:
  504. str = "SDI 5";
  505. break;
  506. case IOSelection::SDI6:
  507. str = "SDI 6";
  508. break;
  509. case IOSelection::SDI7:
  510. str = "SDI 7";
  511. break;
  512. case IOSelection::SDI8:
  513. str = "SDI 8";
  514. break;
  515. case IOSelection::SDI1_2:
  516. str = "SDI 1 & 2";
  517. break;
  518. case IOSelection::SDI3_4:
  519. str = "SDI 3 & 4";
  520. break;
  521. case IOSelection::SDI5_6:
  522. str = "SDI 5 & 6";
  523. break;
  524. case IOSelection::SDI7_8:
  525. str = "SDI 7 & 8";
  526. break;
  527. case IOSelection::SDI1__4:
  528. str = "SDI 1-4";
  529. break;
  530. case IOSelection::SDI5__8:
  531. str = "SDI 5-8";
  532. break;
  533. case IOSelection::HDMI1:
  534. str = "HDMI 1";
  535. break;
  536. case IOSelection::HDMI2:
  537. str = "HDMI 2";
  538. break;
  539. case IOSelection::HDMI3:
  540. str = "HDMI 3";
  541. break;
  542. case IOSelection::HDMI4:
  543. str = "HDMI 4";
  544. break;
  545. case IOSelection::HDMIMonitorIn:
  546. str = "HDMI IN";
  547. break;
  548. case IOSelection::HDMIMonitorOut:
  549. str = "HDMI OUT";
  550. break;
  551. case IOSelection::AnalogIn:
  552. str = "ANALOG IN";
  553. break;
  554. case IOSelection::AnalogOut:
  555. str = "ANALOG OUT";
  556. break;
  557. case IOSelection::Invalid:
  558. str = "Invalid";
  559. break;
  560. }
  561. return str;
  562. }
  563. void IOSelectionToInputSources(IOSelection io, NTV2InputSourceSet &inputSources)
  564. {
  565. switch (io) {
  566. case IOSelection::SDI1:
  567. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  568. break;
  569. case IOSelection::SDI2:
  570. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  571. break;
  572. case IOSelection::SDI3:
  573. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  574. break;
  575. case IOSelection::SDI4:
  576. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  577. break;
  578. case IOSelection::SDI5:
  579. inputSources.insert(NTV2_INPUTSOURCE_SDI5);
  580. break;
  581. case IOSelection::SDI6:
  582. inputSources.insert(NTV2_INPUTSOURCE_SDI6);
  583. break;
  584. case IOSelection::SDI7:
  585. inputSources.insert(NTV2_INPUTSOURCE_SDI7);
  586. break;
  587. case IOSelection::SDI8:
  588. inputSources.insert(NTV2_INPUTSOURCE_SDI8);
  589. break;
  590. case IOSelection::SDI1_2:
  591. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  592. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  593. break;
  594. case IOSelection::SDI3_4:
  595. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  596. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  597. break;
  598. case IOSelection::SDI5_6:
  599. inputSources.insert(NTV2_INPUTSOURCE_SDI5);
  600. inputSources.insert(NTV2_INPUTSOURCE_SDI6);
  601. break;
  602. case IOSelection::SDI7_8:
  603. inputSources.insert(NTV2_INPUTSOURCE_SDI7);
  604. inputSources.insert(NTV2_INPUTSOURCE_SDI8);
  605. break;
  606. case IOSelection::SDI1__4:
  607. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  608. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  609. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  610. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  611. break;
  612. case IOSelection::SDI5__8:
  613. inputSources.insert(NTV2_INPUTSOURCE_SDI5);
  614. inputSources.insert(NTV2_INPUTSOURCE_SDI6);
  615. inputSources.insert(NTV2_INPUTSOURCE_SDI7);
  616. inputSources.insert(NTV2_INPUTSOURCE_SDI8);
  617. break;
  618. case IOSelection::HDMI1:
  619. inputSources.insert(NTV2_INPUTSOURCE_HDMI1);
  620. break;
  621. case IOSelection::HDMI2:
  622. inputSources.insert(NTV2_INPUTSOURCE_HDMI2);
  623. break;
  624. case IOSelection::HDMI3:
  625. inputSources.insert(NTV2_INPUTSOURCE_HDMI3);
  626. break;
  627. case IOSelection::HDMI4:
  628. inputSources.insert(NTV2_INPUTSOURCE_HDMI4);
  629. break;
  630. case IOSelection::HDMIMonitorIn:
  631. inputSources.insert(NTV2_INPUTSOURCE_HDMI1);
  632. break;
  633. case IOSelection::AnalogIn:
  634. inputSources.insert(NTV2_INPUTSOURCE_ANALOG1);
  635. break;
  636. default:
  637. case IOSelection::HDMIMonitorOut:
  638. case IOSelection::AnalogOut:
  639. case IOSelection::Invalid:
  640. break;
  641. }
  642. }
  643. void IOSelectionToOutputDests(IOSelection io, NTV2OutputDestinations &outputDests)
  644. {
  645. switch (io) {
  646. case IOSelection::SDI1:
  647. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI1);
  648. break;
  649. case IOSelection::SDI2:
  650. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI2);
  651. break;
  652. case IOSelection::SDI3:
  653. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI3);
  654. break;
  655. case IOSelection::SDI4:
  656. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI4);
  657. break;
  658. case IOSelection::SDI5:
  659. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI5);
  660. break;
  661. case IOSelection::SDI6:
  662. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI6);
  663. break;
  664. case IOSelection::SDI7:
  665. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI7);
  666. break;
  667. case IOSelection::SDI8:
  668. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI8);
  669. break;
  670. case IOSelection::SDI1_2:
  671. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI1);
  672. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI2);
  673. break;
  674. case IOSelection::SDI3_4:
  675. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI3);
  676. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI4);
  677. break;
  678. case IOSelection::SDI5_6:
  679. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI5);
  680. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI6);
  681. break;
  682. case IOSelection::SDI7_8:
  683. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI7);
  684. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI8);
  685. break;
  686. case IOSelection::SDI1__4:
  687. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI1);
  688. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI2);
  689. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI3);
  690. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI4);
  691. break;
  692. case IOSelection::SDI5__8:
  693. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI5);
  694. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI6);
  695. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI7);
  696. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI8);
  697. break;
  698. case IOSelection::HDMIMonitorOut:
  699. outputDests.insert(NTV2_OUTPUTDESTINATION_HDMI);
  700. break;
  701. case IOSelection::AnalogOut:
  702. outputDests.insert(NTV2_OUTPUTDESTINATION_ANALOG);
  703. break;
  704. default:
  705. case IOSelection::HDMI1:
  706. case IOSelection::HDMI2:
  707. case IOSelection::HDMI3:
  708. case IOSelection::HDMI4:
  709. case IOSelection::HDMIMonitorIn:
  710. case IOSelection::AnalogIn:
  711. case IOSelection::Invalid:
  712. break;
  713. }
  714. }
  715. bool DeviceCanDoIOSelectionIn(NTV2DeviceID id, IOSelection io)
  716. {
  717. // Hide "HDMI1" list selection on devices which have a discrete "HDMI IN" port.
  718. if (io == IOSelection::HDMI1 && CardCanDoHDMIMonitorInput(id)) {
  719. return false;
  720. }
  721. if (io == IOSelection::HDMIMonitorIn && id == DEVICE_ID_KONAHDMI) {
  722. return false;
  723. }
  724. NTV2InputSourceSet inputSources;
  725. if (io != IOSelection::Invalid) {
  726. IOSelectionToInputSources(io, inputSources);
  727. size_t numSrcs = inputSources.size();
  728. size_t canDo = 0;
  729. if (numSrcs > 0) {
  730. for (auto &&inp : inputSources) {
  731. if (NTV2DeviceCanDoInputSource(id, inp))
  732. canDo++;
  733. }
  734. if (canDo == numSrcs)
  735. return true;
  736. }
  737. }
  738. return false;
  739. }
  740. bool DeviceCanDoIOSelectionOut(NTV2DeviceID id, IOSelection io)
  741. {
  742. NTV2OutputDestinations outputDests;
  743. if (io != IOSelection::Invalid) {
  744. IOSelectionToOutputDests(io, outputDests);
  745. size_t numOuts = outputDests.size();
  746. size_t canDo = 0;
  747. if (numOuts > 0) {
  748. for (auto &&out : outputDests) {
  749. if (NTV2DeviceCanDoOutputDestination(id, out))
  750. canDo++;
  751. }
  752. if (canDo == numOuts)
  753. return true;
  754. }
  755. }
  756. return false;
  757. }
  758. bool IsSDIOneWireIOSelection(IOSelection io)
  759. {
  760. bool result = false;
  761. switch (io) {
  762. case IOSelection::SDI1:
  763. case IOSelection::SDI2:
  764. case IOSelection::SDI3:
  765. case IOSelection::SDI4:
  766. case IOSelection::SDI5:
  767. case IOSelection::SDI6:
  768. case IOSelection::SDI7:
  769. case IOSelection::SDI8:
  770. result = true;
  771. break;
  772. default:
  773. result = false;
  774. }
  775. return result;
  776. }
  777. bool IsSDITwoWireIOSelection(IOSelection io)
  778. {
  779. bool result = false;
  780. switch (io) {
  781. case IOSelection::SDI1_2:
  782. case IOSelection::SDI3_4:
  783. case IOSelection::SDI5_6:
  784. case IOSelection::SDI7_8:
  785. result = true;
  786. break;
  787. default:
  788. result = false;
  789. }
  790. return result;
  791. }
  792. bool IsSDIFourWireIOSelection(IOSelection io)
  793. {
  794. bool result = false;
  795. switch (io) {
  796. case IOSelection::SDI1__4:
  797. case IOSelection::SDI5__8:
  798. result = true;
  799. break;
  800. default:
  801. result = false;
  802. }
  803. return result;
  804. }
  805. bool IsMonitorOutputSelection(NTV2DeviceID id, IOSelection io)
  806. {
  807. if (CardCanDoSDIMonitorOutput(id) && io == IOSelection::SDI5)
  808. return true;
  809. if (CardCanDoHDMIMonitorOutput(id) && io == IOSelection::HDMIMonitorOut)
  810. return true;
  811. return false;
  812. }
  813. bool IsIOSelectionSDI(IOSelection io)
  814. {
  815. if (io == IOSelection::SDI1 || io == IOSelection::SDI2 || io == IOSelection::SDI3 || io == IOSelection::SDI4 ||
  816. io == IOSelection::SDI5 || io == IOSelection::SDI6 || io == IOSelection::SDI7 || io == IOSelection::SDI8 ||
  817. io == IOSelection::SDI1_2 || io == IOSelection::SDI3_4 || io == IOSelection::SDI5_6 ||
  818. io == IOSelection::SDI7_8 || io == IOSelection::SDI1__4 || io == IOSelection::SDI5__8) {
  819. return true;
  820. }
  821. return false;
  822. }
  823. bool IsIOSelectionHDMI(IOSelection io)
  824. {
  825. if (io == IOSelection::HDMI1 || io == IOSelection::HDMI2 || io == IOSelection::HDMI3 ||
  826. io == IOSelection::HDMI4 || io == IOSelection::HDMIMonitorIn || io == IOSelection::HDMIMonitorOut) {
  827. return true;
  828. }
  829. return false;
  830. }
  831. std::string MakeCardID(CNTV2Card &card)
  832. {
  833. std::string cardID;
  834. if (card.GetSerialNumberString(cardID)) {
  835. // Try to construct CardID from device ID and serial number...
  836. cardID = NTV2DeviceIDToString(card.GetDeviceID(), false) + "_" + cardID;
  837. } else {
  838. // ...otherwise fall back to the CNTV2DeviceScanner method.
  839. cardID = CNTV2DeviceScanner::GetDeviceRefName(card);
  840. }
  841. return cardID;
  842. }
  843. RasterDefinition DetermineRasterDefinition(NTV2VideoFormat vf)
  844. {
  845. RasterDefinition def = RasterDefinition::Unknown;
  846. if (NTV2_IS_SD_VIDEO_FORMAT(vf)) {
  847. def = RasterDefinition::SD;
  848. } else if (NTV2_IS_HD_VIDEO_FORMAT(vf)) {
  849. def = RasterDefinition::HD;
  850. } else if (NTV2_IS_QUAD_FRAME_FORMAT(vf)) {
  851. def = RasterDefinition::UHD_4K;
  852. } else if (NTV2_IS_QUAD_QUAD_FORMAT(vf)) {
  853. def = RasterDefinition::UHD2_8K;
  854. } else {
  855. def = RasterDefinition::Unknown;
  856. }
  857. return def;
  858. }
  859. inline bool IsStandard1080i(NTV2Standard standard)
  860. {
  861. if (standard == NTV2_STANDARD_1080 || standard == NTV2_STANDARD_2Kx1080i) {
  862. return true;
  863. }
  864. return false;
  865. }
  866. inline bool IsStandard1080p(NTV2Standard standard)
  867. {
  868. if (standard == NTV2_STANDARD_1080p || standard == NTV2_STANDARD_2K || standard == NTV2_STANDARD_2Kx1080p) {
  869. return true;
  870. }
  871. return false;
  872. }
  873. VPIDStandard DetermineVPIDStandard(IOSelection io, NTV2VideoFormat vf, NTV2PixelFormat pf, SDITransport trx,
  874. SDITransport4K t4k)
  875. {
  876. VPIDStandard vpid = VPIDStandard_Unknown;
  877. auto rd = aja::DetermineRasterDefinition(vf);
  878. auto standard = GetNTV2StandardFromVideoFormat(vf);
  879. bool is_rgb = NTV2_IS_FBF_RGB(pf);
  880. bool is_hfr = NTV2_IS_HIGH_NTV2FrameRate(GetNTV2FrameRateFromVideoFormat(vf));
  881. if (rd == RasterDefinition::SD) {
  882. vpid = VPIDStandard_483_576;
  883. } else if (rd == RasterDefinition::HD) {
  884. vpid = VPIDStandard_1080;
  885. if (aja::IsSDIOneWireIOSelection(io)) {
  886. if (is_rgb) {
  887. if (standard == NTV2_STANDARD_720) {
  888. if (trx == SDITransport::SingleLink) {
  889. vpid = VPIDStandard_720;
  890. } else if (trx == SDITransport::SDI3Ga) {
  891. vpid = VPIDStandard_720_3Ga;
  892. } else if (trx == SDITransport::SDI3Gb) {
  893. vpid = VPIDStandard_720_3Gb;
  894. }
  895. } else if (IsStandard1080p(standard)) {
  896. if (trx == SDITransport::SingleLink) {
  897. vpid = VPIDStandard_1080;
  898. } else if (trx == SDITransport::SDI3Ga) {
  899. vpid = VPIDStandard_1080_3Ga;
  900. } else if (trx == SDITransport::SDI3Gb) {
  901. vpid = VPIDStandard_1080_3Gb;
  902. }
  903. }
  904. } else {
  905. if (standard == NTV2_STANDARD_720) {
  906. vpid = VPIDStandard_720;
  907. } else if (IsStandard1080i(standard)) {
  908. vpid = VPIDStandard_1080;
  909. } else if (IsStandard1080p(standard) && trx == SDITransport::SDI3Ga) {
  910. vpid = VPIDStandard_1080_3Ga;
  911. } else if (IsStandard1080p(standard) && trx == SDITransport::SDI3Gb) {
  912. vpid = VPIDStandard_1080_3Gb;
  913. }
  914. }
  915. } else if (aja::IsSDITwoWireIOSelection(io)) {
  916. if (is_rgb) {
  917. if (standard == NTV2_STANDARD_720) {
  918. if (trx == SDITransport::SDI3Ga)
  919. vpid = VPIDStandard_720_3Ga;
  920. else if (trx == SDITransport::SDI3Gb)
  921. vpid = VPIDStandard_720_3Gb;
  922. } else if (IsStandard1080p(standard)) {
  923. if (trx == SDITransport::HDDualLink) {
  924. vpid = VPIDStandard_1080_DualLink;
  925. } else if (trx == SDITransport::SDI3Ga)
  926. vpid = VPIDStandard_1080_Dual_3Ga;
  927. else if (trx == SDITransport::SDI3Gb)
  928. vpid = VPIDStandard_1080_Dual_3Gb;
  929. }
  930. } else {
  931. if (IsStandard1080p(standard) && trx == SDITransport::HDDualLink) {
  932. vpid = VPIDStandard_1080_DualLink;
  933. }
  934. }
  935. }
  936. } else if (rd == RasterDefinition::UHD_4K) {
  937. if (aja::IsSDIOneWireIOSelection(io)) {
  938. if (is_rgb) {
  939. if (trx == SDITransport::SDI6G) {
  940. vpid = VPIDStandard_2160_DualLink;
  941. } else if (trx == SDITransport::SDI12G) {
  942. vpid = VPIDStandard_2160_DualLink_12Gb;
  943. }
  944. } else {
  945. // YCbCr
  946. if (trx == SDITransport::SDI6G) {
  947. vpid = VPIDStandard_2160_Single_6Gb;
  948. } else if (trx == SDITransport::SDI12G) {
  949. vpid = VPIDStandard_2160_Single_12Gb;
  950. } else {
  951. vpid = VPIDStandard_2160_Single_6Gb; // fallback
  952. }
  953. }
  954. } else if (aja::IsSDITwoWireIOSelection(io)) {
  955. if (is_rgb) {
  956. } else {
  957. // YCbCr
  958. if (t4k == SDITransport4K::Squares) {
  959. vpid = VPIDStandard_1080;
  960. } else if (t4k == SDITransport4K::TwoSampleInterleave) {
  961. if (is_hfr && trx == SDITransport::SDI3Ga) {
  962. vpid = VPIDStandard_2160_QuadLink_3Ga;
  963. } else if (is_hfr && trx == SDITransport::SDI3Gb) {
  964. vpid = VPIDStandard_2160_QuadDualLink_3Gb;
  965. } else {
  966. vpid = VPIDStandard_2160_DualLink;
  967. }
  968. }
  969. }
  970. } else if (aja::IsSDIFourWireIOSelection(io)) {
  971. if (is_rgb) {
  972. if (t4k == SDITransport4K::Squares) {
  973. if (trx == SDITransport::SDI3Ga) {
  974. vpid = VPIDStandard_1080_3Ga;
  975. } else if (trx == SDITransport::SDI3Gb) {
  976. vpid = VPIDStandard_1080_DualLink_3Gb;
  977. }
  978. }
  979. } else {
  980. // YCbCr
  981. if (t4k == SDITransport4K::Squares) {
  982. if (trx == SDITransport::SDI3Ga) {
  983. vpid = VPIDStandard_1080_3Ga;
  984. } else if (trx == SDITransport::SDI3Gb) {
  985. vpid = VPIDStandard_1080_DualLink_3Gb;
  986. } else {
  987. vpid = VPIDStandard_1080;
  988. }
  989. } else if (t4k == SDITransport4K::TwoSampleInterleave) {
  990. if (trx == SDITransport::SDI3Ga) {
  991. vpid = VPIDStandard_2160_QuadLink_3Ga;
  992. } else if (trx == SDITransport::SDI3Gb) {
  993. vpid = VPIDStandard_2160_QuadDualLink_3Gb;
  994. }
  995. }
  996. }
  997. }
  998. }
  999. return vpid;
  1000. }
  1001. std::vector<NTV2DeviceID> MultiViewCards()
  1002. {
  1003. return {DEVICE_ID_IOX3};
  1004. }
  1005. } // namespace aja