aja-common.cpp 31 KB

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