aja-common.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  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/ntv2devicescanner.h>
  6. #include <ajantv2/includes/ntv2devicefeatures.h>
  7. #include <ajantv2/includes/ntv2utils.h>
  8. void filter_io_selection_input_list(const std::string &cardID,
  9. const std::string &channelOwner,
  10. obs_property_t *list)
  11. {
  12. auto &cardManager = aja::CardManager::Instance();
  13. auto cardEntry = cardManager.GetCardEntry(cardID);
  14. if (!cardEntry) {
  15. blog(LOG_DEBUG,
  16. "filter_io_selection_input_list: Card Entry not found for %s",
  17. cardID.c_str());
  18. return;
  19. }
  20. NTV2DeviceID deviceID = DEVICE_ID_NOTFOUND;
  21. CNTV2Card *card = cardEntry->GetCard();
  22. if (card)
  23. deviceID = card->GetDeviceID();
  24. // Gray out the IOSelection list items that are in use by other plugin instances
  25. for (size_t idx = 0; idx < obs_property_list_item_count(list); idx++) {
  26. auto io_select = static_cast<IOSelection>(
  27. obs_property_list_item_int(list, idx));
  28. if (io_select == IOSelection::Invalid) {
  29. obs_property_list_item_disable(list, idx, false);
  30. continue;
  31. }
  32. bool enabled = cardEntry->InputSelectionReady(
  33. io_select, deviceID, channelOwner);
  34. obs_property_list_item_disable(list, idx, !enabled);
  35. blog(LOG_DEBUG, "IOSelection %s = %s",
  36. aja::IOSelectionToString(io_select).c_str(),
  37. enabled ? "enabled" : "disabled");
  38. }
  39. }
  40. void filter_io_selection_output_list(const std::string &cardID,
  41. const std::string &channelOwner,
  42. obs_property_t *list)
  43. {
  44. auto &cardManager = aja::CardManager::Instance();
  45. auto cardEntry = cardManager.GetCardEntry(cardID);
  46. if (!cardEntry) {
  47. blog(LOG_DEBUG,
  48. "filter_io_selection_output_list: Card Entry not found for %s",
  49. cardID.c_str());
  50. return;
  51. }
  52. NTV2DeviceID deviceID = DEVICE_ID_NOTFOUND;
  53. CNTV2Card *card = cardEntry->GetCard();
  54. if (card)
  55. deviceID = card->GetDeviceID();
  56. // Gray out the IOSelection list items that are in use by other plugin instances
  57. for (size_t idx = 0; idx < obs_property_list_item_count(list); idx++) {
  58. auto io_select = static_cast<IOSelection>(
  59. obs_property_list_item_int(list, idx));
  60. if (io_select == IOSelection::Invalid) {
  61. obs_property_list_item_disable(list, idx, false);
  62. continue;
  63. }
  64. bool enabled = cardEntry->OutputSelectionReady(
  65. io_select, deviceID, channelOwner);
  66. obs_property_list_item_disable(list, idx, !enabled);
  67. blog(LOG_DEBUG, "IOSelection %s = %s",
  68. aja::IOSelectionToString(io_select).c_str(),
  69. enabled ? "enabled" : "disabled");
  70. }
  71. }
  72. void populate_io_selection_input_list(const std::string &cardID,
  73. const std::string &channelOwner,
  74. NTV2DeviceID deviceID,
  75. obs_property_t *list)
  76. {
  77. obs_property_list_clear(list);
  78. obs_property_list_add_int(list, obs_module_text(kUIPropIOSelect.text),
  79. static_cast<long long>(IOSelection::Invalid));
  80. for (auto i = 0; i < static_cast<int32_t>(IOSelection::NumIOSelections);
  81. i++) {
  82. auto ioSelect = static_cast<IOSelection>(i);
  83. if (ioSelect == IOSelection::SDI1_2_Squares ||
  84. ioSelect == IOSelection::SDI3_4_Squares)
  85. continue;
  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, obs_module_text(kUIPropIOSelect.text),
  102. static_cast<long long>(IOSelection::Invalid));
  103. if (deviceID == DEVICE_ID_TTAP_PRO) {
  104. obs_property_list_add_int(
  105. list, "SDI & HDMI",
  106. static_cast<long long>(IOSelection::HDMIMonitorOut));
  107. } else {
  108. for (auto i = 0;
  109. i < static_cast<int32_t>(IOSelection::NumIOSelections);
  110. i++) {
  111. auto ioSelect = static_cast<IOSelection>(i);
  112. if (ioSelect == IOSelection::Invalid ||
  113. ioSelect == IOSelection::SDI1_2_Squares ||
  114. ioSelect == IOSelection::SDI3_4_Squares)
  115. continue;
  116. if (aja::DeviceCanDoIOSelectionOut(deviceID,
  117. ioSelect)) {
  118. obs_property_list_add_int(
  119. list,
  120. aja::IOSelectionToString(ioSelect)
  121. .c_str(),
  122. static_cast<long long>(ioSelect));
  123. }
  124. }
  125. }
  126. filter_io_selection_output_list(cardID, channelOwner, list);
  127. }
  128. void populate_video_format_list(NTV2DeviceID deviceID, obs_property_t *list,
  129. NTV2VideoFormat genlockFormat)
  130. {
  131. VideoFormatList videoFormats = {};
  132. VideoStandardList orderedStandards = {};
  133. orderedStandards.push_back(NTV2_STANDARD_525);
  134. orderedStandards.push_back(NTV2_STANDARD_625);
  135. if (NTV2DeviceCanDoHDVideo(deviceID)) {
  136. orderedStandards.push_back(NTV2_STANDARD_720);
  137. orderedStandards.push_back(NTV2_STANDARD_1080);
  138. orderedStandards.push_back(NTV2_STANDARD_1080p);
  139. }
  140. if (NTV2DeviceCanDo2KVideo(deviceID)) {
  141. orderedStandards.push_back(NTV2_STANDARD_2K);
  142. orderedStandards.push_back(NTV2_STANDARD_2Kx1080p);
  143. orderedStandards.push_back(NTV2_STANDARD_2Kx1080i);
  144. }
  145. if (NTV2DeviceCanDo4KVideo(deviceID)) {
  146. orderedStandards.push_back(NTV2_STANDARD_3840i);
  147. orderedStandards.push_back(NTV2_STANDARD_3840x2160p);
  148. orderedStandards.push_back(NTV2_STANDARD_3840HFR);
  149. orderedStandards.push_back(NTV2_STANDARD_4096i);
  150. orderedStandards.push_back(NTV2_STANDARD_4096x2160p);
  151. orderedStandards.push_back(NTV2_STANDARD_4096HFR);
  152. }
  153. aja::GetSortedVideoFormats(deviceID, orderedStandards, videoFormats);
  154. for (const auto &vf : videoFormats) {
  155. bool addFormat = true;
  156. // Filter formats by framerate family if specified
  157. if (genlockFormat != NTV2_FORMAT_UNKNOWN)
  158. addFormat = IsMultiFormatCompatible(genlockFormat, vf);
  159. if (addFormat) {
  160. std::string name = NTV2VideoFormatToString(vf, true);
  161. obs_property_list_add_int(list, name.c_str(), (int)vf);
  162. }
  163. }
  164. }
  165. void populate_pixel_format_list(NTV2DeviceID deviceID, obs_property_t *list)
  166. {
  167. const NTV2PixelFormat supported_pix_fmts[] = {kDefaultAJAPixelFormat,
  168. NTV2_FBF_24BIT_BGR};
  169. for (auto &&pf : supported_pix_fmts) {
  170. if (NTV2DeviceCanDoFrameBufferFormat(deviceID, pf)) {
  171. obs_property_list_add_int(
  172. list,
  173. NTV2FrameBufferFormatToString(pf, true).c_str(),
  174. static_cast<long long>(pf));
  175. }
  176. }
  177. }
  178. void populate_sdi_4k_transport_list(obs_property_t *list)
  179. {
  180. obs_property_list_add_int(
  181. list,
  182. aja::SDI4KTransportToString(SDI4KTransport::Squares).c_str(),
  183. static_cast<long long>(SDI4KTransport::Squares));
  184. obs_property_list_add_int(
  185. list,
  186. aja::SDI4KTransportToString(SDI4KTransport::TwoSampleInterleave)
  187. .c_str(),
  188. static_cast<long long>(SDI4KTransport::TwoSampleInterleave));
  189. }
  190. bool aja_video_format_changed(obs_properties_t *props, obs_property_t *list,
  191. obs_data_t *settings)
  192. {
  193. UNUSED_PARAMETER(list);
  194. auto vid_fmt = static_cast<NTV2VideoFormat>(
  195. obs_data_get_int(settings, kUIPropVideoFormatSelect.id));
  196. size_t itemCount = obs_property_list_item_count(list);
  197. bool itemFound = false;
  198. for (size_t i = 0; i < itemCount; i++) {
  199. int itemFormat = obs_property_list_item_int(list, i);
  200. if (itemFormat == vid_fmt) {
  201. itemFound = true;
  202. break;
  203. }
  204. }
  205. if (!itemFound) {
  206. obs_property_list_insert_int(list, 0, "", vid_fmt);
  207. obs_property_list_item_disable(list, 0, true);
  208. return true;
  209. }
  210. obs_property_t *sdi_4k_trx =
  211. obs_properties_get(props, kUIPropSDI4KTransport.id);
  212. obs_property_set_visible(sdi_4k_trx, NTV2_IS_4K_VIDEO_FORMAT(vid_fmt));
  213. return true;
  214. }
  215. namespace aja {
  216. video_format AJAPixelFormatToOBSVideoFormat(NTV2PixelFormat pf)
  217. {
  218. video_format obs_video_format = VIDEO_FORMAT_NONE;
  219. switch (pf) {
  220. case NTV2_FBF_8BIT_YCBCR:
  221. obs_video_format = VIDEO_FORMAT_UYVY;
  222. break;
  223. case NTV2_FBF_24BIT_RGB:
  224. case NTV2_FBF_24BIT_BGR:
  225. obs_video_format = VIDEO_FORMAT_BGR3;
  226. break;
  227. case NTV2_FBF_ARGB:
  228. case NTV2_FBF_ABGR:
  229. case NTV2_FBF_RGBA:
  230. obs_video_format = VIDEO_FORMAT_BGRA;
  231. break;
  232. case NTV2_FBF_10BIT_YCBCR:
  233. case NTV2_FBF_10BIT_RGB:
  234. case NTV2_FBF_8BIT_YCBCR_YUY2:
  235. case NTV2_FBF_10BIT_DPX:
  236. case NTV2_FBF_10BIT_YCBCR_DPX:
  237. case NTV2_FBF_8BIT_DVCPRO:
  238. case NTV2_FBF_8BIT_YCBCR_420PL3:
  239. case NTV2_FBF_8BIT_HDV:
  240. case NTV2_FBF_10BIT_YCBCRA:
  241. case NTV2_FBF_10BIT_DPX_LE:
  242. case NTV2_FBF_48BIT_RGB:
  243. case NTV2_FBF_12BIT_RGB_PACKED:
  244. case NTV2_FBF_PRORES_DVCPRO:
  245. case NTV2_FBF_PRORES_HDV:
  246. case NTV2_FBF_10BIT_RGB_PACKED:
  247. case NTV2_FBF_10BIT_ARGB:
  248. case NTV2_FBF_16BIT_ARGB:
  249. case NTV2_FBF_8BIT_YCBCR_422PL3:
  250. case NTV2_FBF_10BIT_RAW_RGB:
  251. case NTV2_FBF_10BIT_RAW_YCBCR:
  252. case NTV2_FBF_10BIT_YCBCR_420PL3_LE:
  253. case NTV2_FBF_10BIT_YCBCR_422PL3_LE:
  254. case NTV2_FBF_10BIT_YCBCR_420PL2:
  255. case NTV2_FBF_10BIT_YCBCR_422PL2:
  256. case NTV2_FBF_8BIT_YCBCR_420PL2:
  257. case NTV2_FBF_8BIT_YCBCR_422PL2:
  258. default:
  259. obs_video_format = VIDEO_FORMAT_NONE;
  260. break;
  261. }
  262. return obs_video_format;
  263. }
  264. void GetSortedVideoFormats(NTV2DeviceID id, const VideoStandardList &standards,
  265. VideoFormatList &videoFormats)
  266. {
  267. if (standards.empty())
  268. return;
  269. VideoFormatMap videoFormatMap;
  270. // Bin all the formats based on video standard
  271. for (size_t i = (size_t)NTV2_FORMAT_UNKNOWN;
  272. i < (size_t)NTV2_MAX_NUM_VIDEO_FORMATS; i++) {
  273. NTV2VideoFormat fmt = (NTV2VideoFormat)i;
  274. NTV2Standard standard = GetNTV2StandardFromVideoFormat(fmt);
  275. bool addFmt = true;
  276. if (id != DEVICE_ID_NOTFOUND) {
  277. addFmt = NTV2DeviceCanDoVideoFormat(id, fmt);
  278. }
  279. if (addFmt) {
  280. if (videoFormatMap.count(standard)) {
  281. videoFormatMap.at(standard).push_back(fmt);
  282. } else {
  283. std::vector<NTV2VideoFormat> v;
  284. v.push_back(fmt);
  285. videoFormatMap.insert(
  286. std::pair<NTV2Standard,
  287. std::vector<NTV2VideoFormat>>(
  288. standard, v));
  289. }
  290. }
  291. }
  292. for (size_t v = (size_t)NTV2_STANDARD_1080;
  293. v < (size_t)NTV2_NUM_STANDARDS; v++) {
  294. NTV2Standard standard = (NTV2Standard)v;
  295. if (videoFormatMap.count(standard)) {
  296. std::sort(videoFormatMap.at(standard).begin(),
  297. videoFormatMap.at(standard).end(),
  298. [&](const NTV2VideoFormat &d1,
  299. const NTV2VideoFormat &d2) {
  300. std::string d1Str, d2Str;
  301. d1Str = NTV2VideoFormatToString(d1);
  302. d2Str = NTV2VideoFormatToString(d2);
  303. return d1Str < d2Str;
  304. });
  305. }
  306. }
  307. for (size_t v = 0; v < standards.size(); v++) {
  308. NTV2Standard standard = standards.at(v);
  309. if (videoFormatMap.count(standard)) {
  310. for (size_t i = 0;
  311. i < videoFormatMap.at(standard).size(); i++) {
  312. NTV2VideoFormat vf =
  313. videoFormatMap.at(standard).at(i);
  314. videoFormats.push_back(vf);
  315. }
  316. }
  317. }
  318. }
  319. uint32_t CardNumFramestores(NTV2DeviceID id)
  320. {
  321. auto numFramestores = NTV2DeviceGetNumFrameStores(id);
  322. if (id == DEVICE_ID_CORVIDHBR) {
  323. numFramestores = 1;
  324. }
  325. return numFramestores;
  326. }
  327. uint32_t CardNumAudioSystems(NTV2DeviceID id)
  328. {
  329. if (id == DEVICE_ID_KONALHI || id == DEVICE_ID_KONALHEPLUS)
  330. return 2;
  331. return NTV2DeviceGetNumAudioSystems(id);
  332. }
  333. // IO4K and IO4K+ perform SDI Monitor Output on "SDI5" and "Framestore 4".
  334. bool CardCanDoSDIMonitorOutput(NTV2DeviceID id)
  335. {
  336. return (id == DEVICE_ID_IO4K || id == DEVICE_ID_IO4KPLUS);
  337. }
  338. // Cards with a dedicated HDMI Monitor Output tie it to "Framestore 4".
  339. bool CardCanDoHDMIMonitorOutput(NTV2DeviceID id)
  340. {
  341. return (id == DEVICE_ID_IO4K || id == DEVICE_ID_IO4KPLUS ||
  342. id == DEVICE_ID_IOXT || id == DEVICE_ID_IOX3 ||
  343. id == DEVICE_ID_KONA4 || id == DEVICE_ID_KONA5 ||
  344. id == DEVICE_ID_KONA5_8K || id == DEVICE_ID_KONA5_2X4K ||
  345. id == DEVICE_ID_KONA5_8KMK);
  346. }
  347. // Cards capable of 1x SDI at 6G/12G.
  348. bool CardCanDo1xSDI12G(NTV2DeviceID id)
  349. {
  350. return (id == DEVICE_ID_KONA5_8K || id == DEVICE_ID_KONA5_8KMK ||
  351. id == DEVICE_ID_KONA5 || id == DEVICE_ID_KONA5_2X4K ||
  352. id == DEVICE_ID_IO4KPLUS || id == DEVICE_ID_CORVID44_12G);
  353. }
  354. // Check for 3G level-B SDI on the wire.
  355. bool Is3GLevelB(CNTV2Card *card, NTV2Channel channel)
  356. {
  357. if (!card)
  358. return false;
  359. bool levelB = false;
  360. auto deviceID = card->GetDeviceID();
  361. UWord channelIndex = static_cast<UWord>(channel);
  362. if (NTV2DeviceCanDo3GIn(deviceID, channelIndex) ||
  363. NTV2DeviceCanDo12GIn(deviceID, channelIndex)) {
  364. if (!card->GetSDIInput3GbPresent(levelB, channel))
  365. return false;
  366. }
  367. return levelB;
  368. }
  369. // Get the 3G Level-A enum for a 3G Level-B format enum.
  370. NTV2VideoFormat GetLevelAFormatForLevelBFormat(NTV2VideoFormat vf)
  371. {
  372. NTV2VideoFormat result = vf;
  373. switch (vf) {
  374. default:
  375. break;
  376. case NTV2_FORMAT_1080p_5000_B:
  377. result = NTV2_FORMAT_1080p_5000_A;
  378. break;
  379. case NTV2_FORMAT_1080p_5994_B:
  380. result = NTV2_FORMAT_1080p_5994_A;
  381. break;
  382. case NTV2_FORMAT_1080p_6000_B:
  383. result = NTV2_FORMAT_1080p_6000_A;
  384. break;
  385. case NTV2_FORMAT_1080p_2K_4795_B:
  386. result = NTV2_FORMAT_1080p_2K_4795_A;
  387. break;
  388. case NTV2_FORMAT_1080p_2K_4800_B:
  389. result = NTV2_FORMAT_1080p_2K_4800_A;
  390. break;
  391. case NTV2_FORMAT_1080p_2K_5000_B:
  392. result = NTV2_FORMAT_1080p_2K_5000_A;
  393. break;
  394. case NTV2_FORMAT_1080p_2K_5994_B:
  395. result = NTV2_FORMAT_1080p_2K_5994_A;
  396. break;
  397. case NTV2_FORMAT_1080p_2K_6000_B:
  398. result = NTV2_FORMAT_1080p_2K_6000_A;
  399. break;
  400. }
  401. return result;
  402. }
  403. NTV2VideoFormat InterlacedFormatForPsfFormat(NTV2VideoFormat vf)
  404. {
  405. NTV2VideoFormat result = vf;
  406. switch (vf) {
  407. default:
  408. break;
  409. case NTV2_FORMAT_1080psf_2500_2:
  410. result = NTV2_FORMAT_1080i_5000;
  411. break;
  412. case NTV2_FORMAT_1080psf_2997_2:
  413. result = NTV2_FORMAT_1080i_5994;
  414. break;
  415. }
  416. return result;
  417. }
  418. // Certain cards only have 1 SDI spigot.
  419. bool IsSingleSDIDevice(NTV2DeviceID id)
  420. {
  421. return (id == DEVICE_ID_TTAP_PRO || id == DEVICE_ID_KONA1);
  422. }
  423. bool IsIODevice(NTV2DeviceID id)
  424. {
  425. return (id == DEVICE_ID_IOXT || id == DEVICE_ID_IOX3 ||
  426. id == DEVICE_ID_IO4K || id == DEVICE_ID_IO4KPLUS ||
  427. id == DEVICE_ID_IOIP_2022 || id == DEVICE_ID_IOIP_2110);
  428. }
  429. bool IsRetailSDI12G(NTV2DeviceID id)
  430. {
  431. return (id == DEVICE_ID_KONA5 || id == DEVICE_ID_IO4KPLUS);
  432. }
  433. bool IsOutputOnlyDevice(NTV2DeviceID id)
  434. {
  435. return id == DEVICE_ID_TTAP_PRO;
  436. }
  437. std::string SDI4KTransportToString(SDI4KTransport mode)
  438. {
  439. std::string str = "";
  440. switch (mode) {
  441. case SDI4KTransport::Squares:
  442. str = "Squares";
  443. break;
  444. case SDI4KTransport::TwoSampleInterleave:
  445. str = "2SI";
  446. break;
  447. default:
  448. case SDI4KTransport::Unknown:
  449. str = "Unknown";
  450. break;
  451. }
  452. return str;
  453. }
  454. std::string IOSelectionToString(IOSelection io)
  455. {
  456. std::string str;
  457. switch (io) {
  458. case IOSelection::SDI1:
  459. str = "SDI 1";
  460. break;
  461. case IOSelection::SDI2:
  462. str = "SDI 2";
  463. break;
  464. case IOSelection::SDI3:
  465. str = "SDI 3";
  466. break;
  467. case IOSelection::SDI4:
  468. str = "SDI 4";
  469. break;
  470. case IOSelection::SDI5:
  471. str = "SDI 5";
  472. break;
  473. case IOSelection::SDI6:
  474. str = "SDI 6";
  475. break;
  476. case IOSelection::SDI7:
  477. str = "SDI 7";
  478. break;
  479. case IOSelection::SDI8:
  480. str = "SDI 8";
  481. break;
  482. case IOSelection::SDI1_2:
  483. str = "SDI 1 & 2";
  484. break;
  485. case IOSelection::SDI1_2_Squares:
  486. str = "SDI 1 & 2 (4K Squares)";
  487. break;
  488. case IOSelection::SDI3_4:
  489. str = "SDI 3 & 4";
  490. break;
  491. case IOSelection::SDI3_4_Squares:
  492. str = "SDI 3 & 4 (4K Squares)";
  493. break;
  494. case IOSelection::SDI5_6:
  495. str = "SDI 5 & 6";
  496. break;
  497. case IOSelection::SDI7_8:
  498. str = "SDI 7 & 8";
  499. break;
  500. case IOSelection::SDI1__4:
  501. str = "SDI 1-4";
  502. break;
  503. case IOSelection::SDI5__8:
  504. str = "SDI 5-8";
  505. break;
  506. case IOSelection::HDMI1:
  507. str = "HDMI 1";
  508. break;
  509. case IOSelection::HDMI2:
  510. str = "HDMI 2";
  511. break;
  512. case IOSelection::HDMI3:
  513. str = "HDMI 3";
  514. break;
  515. case IOSelection::HDMI4:
  516. str = "HDMI 4";
  517. break;
  518. case IOSelection::HDMIMonitorIn:
  519. str = "HDMI Monitor In";
  520. break;
  521. case IOSelection::HDMIMonitorOut:
  522. str = "HDMI Monitor Out";
  523. break;
  524. case IOSelection::AnalogIn:
  525. str = "Analog In";
  526. break;
  527. case IOSelection::AnalogOut:
  528. str = "Analog Out";
  529. break;
  530. case IOSelection::Invalid:
  531. str = "Invalid";
  532. break;
  533. }
  534. return str;
  535. }
  536. void IOSelectionToInputSources(IOSelection io, NTV2InputSourceSet &inputSources)
  537. {
  538. switch (io) {
  539. case IOSelection::SDI1:
  540. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  541. break;
  542. case IOSelection::SDI2:
  543. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  544. break;
  545. case IOSelection::SDI3:
  546. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  547. break;
  548. case IOSelection::SDI4:
  549. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  550. break;
  551. case IOSelection::SDI5:
  552. inputSources.insert(NTV2_INPUTSOURCE_SDI5);
  553. break;
  554. case IOSelection::SDI6:
  555. inputSources.insert(NTV2_INPUTSOURCE_SDI6);
  556. break;
  557. case IOSelection::SDI7:
  558. inputSources.insert(NTV2_INPUTSOURCE_SDI7);
  559. break;
  560. case IOSelection::SDI8:
  561. inputSources.insert(NTV2_INPUTSOURCE_SDI8);
  562. break;
  563. case IOSelection::SDI1_2:
  564. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  565. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  566. break;
  567. case IOSelection::SDI1_2_Squares:
  568. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  569. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  570. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  571. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  572. break;
  573. case IOSelection::SDI3_4:
  574. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  575. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  576. break;
  577. case IOSelection::SDI3_4_Squares:
  578. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  579. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  580. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  581. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  582. break;
  583. case IOSelection::SDI5_6:
  584. inputSources.insert(NTV2_INPUTSOURCE_SDI5);
  585. inputSources.insert(NTV2_INPUTSOURCE_SDI6);
  586. break;
  587. case IOSelection::SDI7_8:
  588. inputSources.insert(NTV2_INPUTSOURCE_SDI7);
  589. inputSources.insert(NTV2_INPUTSOURCE_SDI8);
  590. break;
  591. case IOSelection::SDI1__4:
  592. inputSources.insert(NTV2_INPUTSOURCE_SDI1);
  593. inputSources.insert(NTV2_INPUTSOURCE_SDI2);
  594. inputSources.insert(NTV2_INPUTSOURCE_SDI3);
  595. inputSources.insert(NTV2_INPUTSOURCE_SDI4);
  596. break;
  597. case IOSelection::SDI5__8:
  598. inputSources.insert(NTV2_INPUTSOURCE_SDI5);
  599. inputSources.insert(NTV2_INPUTSOURCE_SDI6);
  600. inputSources.insert(NTV2_INPUTSOURCE_SDI7);
  601. inputSources.insert(NTV2_INPUTSOURCE_SDI8);
  602. break;
  603. case IOSelection::HDMI1:
  604. inputSources.insert(NTV2_INPUTSOURCE_HDMI1);
  605. break;
  606. case IOSelection::HDMI2:
  607. inputSources.insert(NTV2_INPUTSOURCE_HDMI2);
  608. break;
  609. case IOSelection::HDMI3:
  610. inputSources.insert(NTV2_INPUTSOURCE_HDMI3);
  611. break;
  612. case IOSelection::HDMI4:
  613. inputSources.insert(NTV2_INPUTSOURCE_HDMI4);
  614. break;
  615. case IOSelection::HDMIMonitorIn:
  616. inputSources.insert(NTV2_INPUTSOURCE_HDMI1);
  617. break;
  618. case IOSelection::AnalogIn:
  619. inputSources.insert(NTV2_INPUTSOURCE_ANALOG1);
  620. break;
  621. default:
  622. case IOSelection::HDMIMonitorOut:
  623. case IOSelection::AnalogOut:
  624. case IOSelection::Invalid:
  625. break;
  626. }
  627. }
  628. void IOSelectionToOutputDests(IOSelection io,
  629. NTV2OutputDestinations &outputDests)
  630. {
  631. switch (io) {
  632. case IOSelection::SDI1:
  633. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI1);
  634. break;
  635. case IOSelection::SDI2:
  636. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI2);
  637. break;
  638. case IOSelection::SDI3:
  639. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI3);
  640. break;
  641. case IOSelection::SDI4:
  642. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI4);
  643. break;
  644. case IOSelection::SDI5:
  645. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI5);
  646. break;
  647. case IOSelection::SDI6:
  648. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI6);
  649. break;
  650. case IOSelection::SDI7:
  651. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI7);
  652. break;
  653. case IOSelection::SDI8:
  654. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI8);
  655. break;
  656. case IOSelection::SDI1_2:
  657. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI1);
  658. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI2);
  659. break;
  660. // Requires 4x framestores and 2x SDI spigots
  661. case IOSelection::SDI1_2_Squares:
  662. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI1);
  663. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI2);
  664. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI3);
  665. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI4);
  666. break;
  667. case IOSelection::SDI3_4:
  668. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI3);
  669. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI4);
  670. break;
  671. // Requires 4x framestores and 2x SDI spigots
  672. case IOSelection::SDI3_4_Squares:
  673. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI1);
  674. outputDests.insert(NTV2_OUTPUTDESTINATION_SDI2);
  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. NTV2InputSourceSet inputSources;
  718. if (io != IOSelection::Invalid) {
  719. IOSelectionToInputSources(io, inputSources);
  720. size_t numSrcs = inputSources.size();
  721. size_t canDo = 0;
  722. if (numSrcs > 0) {
  723. for (auto &&inp : inputSources) {
  724. if (NTV2DeviceCanDoInputSource(id, inp))
  725. canDo++;
  726. }
  727. if (canDo == numSrcs)
  728. return true;
  729. }
  730. }
  731. return false;
  732. }
  733. bool DeviceCanDoIOSelectionOut(NTV2DeviceID id, IOSelection io)
  734. {
  735. NTV2OutputDestinations outputDests;
  736. if (io != IOSelection::Invalid) {
  737. IOSelectionToOutputDests(io, outputDests);
  738. size_t numOuts = outputDests.size();
  739. size_t canDo = 0;
  740. if (numOuts > 0) {
  741. for (auto &&out : outputDests) {
  742. if (NTV2DeviceCanDoOutputDestination(id, out))
  743. canDo++;
  744. }
  745. if (canDo == numOuts)
  746. return true;
  747. }
  748. }
  749. return false;
  750. }
  751. bool IsSDIOneWireIOSelection(IOSelection io)
  752. {
  753. bool result = false;
  754. switch (io) {
  755. case IOSelection::SDI1:
  756. case IOSelection::SDI2:
  757. case IOSelection::SDI3:
  758. case IOSelection::SDI4:
  759. case IOSelection::SDI5:
  760. case IOSelection::SDI6:
  761. case IOSelection::SDI7:
  762. case IOSelection::SDI8:
  763. result = true;
  764. break;
  765. default:
  766. result = false;
  767. }
  768. return result;
  769. }
  770. bool IsSDITwoWireIOSelection(IOSelection io)
  771. {
  772. bool result = false;
  773. switch (io) {
  774. case IOSelection::SDI1_2:
  775. case IOSelection::SDI1_2_Squares:
  776. case IOSelection::SDI3_4:
  777. case IOSelection::SDI3_4_Squares:
  778. case IOSelection::SDI5_6:
  779. case IOSelection::SDI7_8:
  780. result = true;
  781. break;
  782. default:
  783. result = false;
  784. }
  785. return result;
  786. }
  787. bool IsSDIFourWireIOSelection(IOSelection io)
  788. {
  789. bool result = false;
  790. switch (io) {
  791. case IOSelection::SDI1__4:
  792. case IOSelection::SDI5__8:
  793. result = true;
  794. break;
  795. default:
  796. result = false;
  797. }
  798. return result;
  799. }
  800. bool IsMonitorOutputSelection(NTV2DeviceID id, IOSelection io)
  801. {
  802. if (CardCanDoSDIMonitorOutput(id) && io == IOSelection::SDI5)
  803. return true;
  804. if (CardCanDoHDMIMonitorOutput(id) && io == IOSelection::HDMIMonitorOut)
  805. return true;
  806. return false;
  807. }
  808. std::string MakeCardID(CNTV2Card &card)
  809. {
  810. std::string cardID;
  811. if (card.GetSerialNumberString(cardID)) {
  812. // Try to construct CardID from device ID and serial number...
  813. cardID = NTV2DeviceIDToString(card.GetDeviceID(), false) + "_" +
  814. cardID;
  815. } else {
  816. // ...otherwise fall back to the CNTV2DeviceScanner method.
  817. cardID = CNTV2DeviceScanner::GetDeviceRefName(card);
  818. }
  819. return cardID;
  820. }
  821. } // aja