aja-common.cpp 31 KB

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