From e0a1d4fca9f2200681fca03d4d30e2dbce908d76 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Mon, 10 Jun 2024 09:51:15 +0200 Subject: [PATCH] deck: return back original numeric indices The numeric indices now use the "natural" index as devices given by IDeckLinkIterator. The idea is to keep the index consistent with previous versions. For the devices ordered newly by topological ID, use character indices instead ('a', 'b' etc.). Do not advertise numeric indices for now, anyways, even though now left - it can now be considered as a legacy feature, it can be later added to the output if considered useful. --- src/blackmagic_common.cpp | 25 +++++++++++++------ src/blackmagic_common.hpp | 12 +++++++++- src/video_capture/decklink.cpp | 44 +++++++++++++++++----------------- src/video_display/decklink.cpp | 34 ++++++++++++++++---------- 4 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/blackmagic_common.cpp b/src/blackmagic_common.cpp index bd64f4ed5..ab73d598d 100644 --- a/src/blackmagic_common.cpp +++ b/src/blackmagic_common.cpp @@ -1097,12 +1097,12 @@ print_bmd_attribute(IDeckLinkProfileAttributes *deckLinkAttributes, * take care about the returned object lifetime (particularly not to * be destroyed after decklink_uninitialize()). */ -std::map> +std::vector bmd_get_sorted_devices(IDeckLinkIterator *deckLinkIterator) { IDeckLink *deckLink = nullptr; - std::map> out; - unsigned tid_substitute = UINT_MAX; + std::vector out; + int idx = 0; while (deckLinkIterator->Next(&deckLink) == S_OK) { IDeckLinkProfileAttributes *deckLinkAttributes = nullptr; HRESULT result = E_FAIL; @@ -1114,15 +1114,26 @@ bmd_get_sorted_devices(IDeckLinkIterator *deckLinkIterator) result = deckLinkAttributes->GetInt(BMDDeckLinkTopologicalID, &id); if (result != S_OK) { - id = tid_substitute--; + id = UINT_MAX - idx; } assert(id >= 0 && id <= UINT_MAX); deckLinkAttributes->Release(); auto release = [](IDeckLink *d) { d->Release(); }; - out.emplace(id, - std::unique_ptr{ - deckLink, release }); + auto &it = out.emplace_back( + std::unique_ptr{ + deckLink, release }, + 0, 0, 0); + std::get(it) = id; + std::get(it) = idx++; + } + std::sort(out.begin(), out.end(), [](bmd_dev &a, bmd_dev &b) { + return std::get(a) < std::get(b); + }); + // assign new indices + char new_idx = 'a'; + for (auto &d : out) { + std::get(d) = new_idx++; } return out; } diff --git a/src/blackmagic_common.hpp b/src/blackmagic_common.hpp index f22cdd699..771e8bbc5 100644 --- a/src/blackmagic_common.hpp +++ b/src/blackmagic_common.hpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -175,7 +176,16 @@ bool bmd_parse_audio_levels(const char *opt) noexcept(false); void print_bmd_attribute(IDeckLinkProfileAttributes *deckLinkAttributes, const char *query_prop_fcc); -std::map> +/** + * @details parameters: + * - first - IDeckLinkInstance + * - unsigned - topological ID + * - int - natural idx (the old, order as given by IDeckLinkIterator) + * - char - new index ('a', 'b', 'c'...); sorted by topological ID + */ +using bmd_dev = std::tuple, + unsigned, int, char>; +std::vector bmd_get_sorted_devices(IDeckLinkIterator *deckLinkIterator); #endif // defined BLACKMAGIC_COMMON_HPP diff --git a/src/video_capture/decklink.cpp b/src/video_capture/decklink.cpp index 38bde49da..4b13ea038 100644 --- a/src/video_capture/decklink.cpp +++ b/src/video_capture/decklink.cpp @@ -614,16 +614,16 @@ decklink_help(bool full, const char *query_prop_fcc = nullptr) // Enumerate all cards in this system int numDevices = 0; for (auto &d : bmd_get_sorted_devices(deckLinkIterator)) { - IDeckLink *deckLink = d.second.get(); + IDeckLink *deckLink = get<0>(d).get(); string deviceName = bmd_get_device_name(deckLink); if (deviceName.empty()) { deviceName = "(unable to get name)"; } // *** Print the model name of the DeckLink card - color_printf("\t" TBOLD("%d") ") " TBOLD("%6x") ") " TBOLD( - TGREEN("%s")) "\n", - numDevices, d.first, deviceName.c_str()); + color_printf("\t" TBOLD("%c") ") " TBOLD("%6x") ") " TBOLD( + TGREEN("%s")) "\n", + get(d), get(d), deviceName.c_str()); // Increment the total number of DeckLink cards found numDevices++; @@ -638,8 +638,6 @@ decklink_help(bool full, const char *query_prop_fcc = nullptr) "fullhelp") "\" to see full list of device modes " "and available connections)\n\n"; } - - deckLinkIterator->Release(); decklink_uninitialize(&com_initialized); @@ -653,9 +651,9 @@ decklink_help(bool full, const char *query_prop_fcc = nullptr) col() << "\t" << SBOLD(uv_argv[0] << " -t decklink") << " # captures autodetected video from first DeckLink (index 0) " "in system\n"; - col() - << "\t" << SBOLD(uv_argv[0] << " -t decklink:d=1:m=Hp30:c=v210") - << " # specify mode for device which doesn't have autodetection\n"; + col() << "\t" << SBOLD(uv_argv[0] << " -t decklink:d=b:m=Hp30:c=v210") + << " # specify mode for 2nd device which doesn't have " + "autodetection\n"; col() << "\t" << SBOLD(uv_argv[0] << " -t decklink:d=\"DeckLink 8K Pro (1)\":profile=1dfd") @@ -832,7 +830,6 @@ static void vidcap_decklink_probe(device_info **available_cards, int *card_count *deleter = free; IDeckLinkIterator* deckLinkIterator; - int numDevices = 0; // Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system bool com_initialized = false; @@ -843,7 +840,7 @@ static void vidcap_decklink_probe(device_info **available_cards, int *card_count // Enumerate all cards in this system for (auto &d : bmd_get_sorted_devices(deckLinkIterator)) { - IDeckLink *deckLink = d.second.get(); + IDeckLink *deckLink = get<0>(d).get(); HRESULT result; IDeckLinkProfileAttributes *deckLinkAttributes; @@ -867,7 +864,7 @@ static void vidcap_decklink_probe(device_info **available_cards, int *card_count realloc(cards, *card_count * sizeof(struct device_info)); memset(&cards[*card_count - 1], 0, sizeof(struct device_info)); snprintf(cards[*card_count - 1].dev, sizeof cards[*card_count - 1].dev, - ":device=%d", numDevices); + ":device=%u", get(d)); snprintf(cards[*card_count - 1].name, sizeof cards[*card_count - 1].name, "%s", deviceName.c_str()); snprintf(cards[*card_count - 1].extra, sizeof cards[*card_count - 1].extra, @@ -930,9 +927,6 @@ static void vidcap_decklink_probe(device_info **available_cards, int *card_count dev_add_option(&cards[*card_count - 1], "3D", "3D", "3D", ":3D", true); dev_add_option(&cards[*card_count - 1], "Profile", "Duplex profile can be one of: 1dhd, 2dhd, 2dfd, 4dhd, keep", "profile", ":profile=", false); - // Increment the total number of DeckLink cards found - numDevices++; - RELEASE_IF_NOT_NULL(deckLinkAttributes); } @@ -1113,7 +1107,6 @@ bool device_state::init(struct vidcap_decklink_state *s, struct tile *t, BMDAudi tile = t; - int dnum = 0; bool com_initialized = false; // Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system IDeckLinkIterator *deckLinkIterator = create_decklink_iterator(&com_initialized, true, false); @@ -1121,7 +1114,7 @@ bool device_state::init(struct vidcap_decklink_state *s, struct tile *t, BMDAudi return false; } for (auto &d : bmd_get_sorted_devices(deckLinkIterator)) { - deckLink = d.second.release(); // we must release manually! + deckLink = get<0>(d).release(); // we must release manually! string deviceName = bmd_get_device_name(deckLink); if (!deviceName.empty() && deviceName == device_id.c_str()) { break; @@ -1130,15 +1123,22 @@ bool device_state::init(struct vidcap_decklink_state *s, struct tile *t, BMDAudi // topological ID const unsigned long tid = strtoul(device_id.c_str(), nullptr, 16); - if (d.first == tid) { + if (get(d) == tid) { break; } - // idx - if (isdigit(device_id.c_str()[0]) && atoi(device_id.c_str()) == dnum) { - break; + // natural (old) index + if (isdigit(device_id.c_str()[0])) { + if (atoi(device_id.c_str()) == get(d)) { + break; + } + } + // new (character) index + if (device_id.length() == 1 && device_id[0] >= 'a') { + if (device_id[0] == get(d)) { + break; + } } - dnum++; // Release the IDeckLink instance when we've finished with it to prevent leaks deckLink->Release(); deckLink = NULL; diff --git a/src/video_display/decklink.cpp b/src/video_display/decklink.cpp index 07b8a91f3..3de92e25e 100644 --- a/src/video_display/decklink.cpp +++ b/src/video_display/decklink.cpp @@ -130,6 +130,7 @@ using std::atomic_bool; using std::cout; using std::copy; using std::exception; +using std::get; using std::invalid_argument; using std::lock_guard; using std::map; @@ -637,16 +638,17 @@ show_help(bool full, const char *query_prop_fcc = nullptr) // Enumerate all cards in this system for (auto &d : bmd_get_sorted_devices(deckLinkIterator)) { - IDeckLink *deckLink = d.second.get(); + IDeckLink *deckLink = get<0>(d).get(); string deviceName = bmd_get_device_name(deckLink); if (deviceName.empty()) { deviceName = "(unable to get name)"; } // *** Print the model name of the DeckLink card - color_printf("\t" TBOLD("%d") ") " TBOLD("%6x") ") " TBOLD( + color_printf("\t" TBOLD("%c") ") " TBOLD("%6x") ") " TBOLD( TGREEN("%s")) "\n", - numDevices, d.first, deviceName.c_str()); + get(d), get(d), + deviceName.c_str()); if (full) { print_output_modes(deckLink, query_prop_fcc); } @@ -1134,7 +1136,7 @@ static void display_decklink_probe(struct device_info **available_cards, int *co // Enumerate all cards in this system for (auto &d : bmd_get_sorted_devices(deckLinkIterator)) { - IDeckLink *deckLink = d.second.get(); + IDeckLink *deckLink = get<0>(d).get(); string deviceName = bmd_get_device_name(deckLink); if (deviceName.empty()) { deviceName = "(unknown)"; @@ -1144,7 +1146,9 @@ static void display_decklink_probe(struct device_info **available_cards, int *co *available_cards = (struct device_info *) realloc(*available_cards, *count * sizeof(struct device_info)); memset(*available_cards + *count - 1, 0, sizeof(struct device_info)); - snprintf((*available_cards)[*count - 1].dev, sizeof (*available_cards)[*count - 1].dev, ":device=%d", *count - 1); + snprintf((*available_cards)[*count - 1].dev, + sizeof(*available_cards)[*count - 1].dev, ":device=%u", + get(d)); snprintf((*available_cards)[*count - 1].extra, sizeof (*available_cards)[*count - 1].extra, "\"embeddedAudioAvailable\":\"t\""); (*available_cards)[*count - 1].repeatable = false; @@ -1387,7 +1391,6 @@ static void *display_decklink_init(struct module *parent, const char *fmt, unsig IDeckLinkIterator* deckLinkIterator; HRESULT result; string cardId("0"); - int dnum = 0; IDeckLinkConfiguration* deckLinkConfiguration = NULL; // for Decklink Studio which has switchable XLR - analog 3 and 4 or AES/EBU 3,4 and 5,6 @@ -1433,7 +1436,7 @@ static void *display_decklink_init(struct module *parent, const char *fmt, unsig // Connect to the first DeckLink instance for (auto &d : bmd_get_sorted_devices(deckLinkIterator)) { - s->deckLink = d.second.release(); // unmanage + s->deckLink = get<0>(d).release(); // unmanage string deviceName = bmd_get_device_name(s->deckLink); if (!deviceName.empty() && deviceName == cardId) { @@ -1441,17 +1444,24 @@ static void *display_decklink_init(struct module *parent, const char *fmt, unsig } // topological ID const unsigned long tid = strtoul(cardId.c_str(), nullptr, 16); - if (d.first == tid) { + if (get(d) == tid) { break; } - // idx - if (isdigit(cardId.c_str()[0]) && dnum == atoi(cardId.c_str())) { - break; + // natural (old) index + if (isdigit(cardId.c_str()[0])) { + if (atoi(cardId.c_str()) == get(d)) { + break; + } + } + // new (character) index + if (cardId.length() == 1 && cardId[0] >= 'a') { + if (cardId[0] == get(d)) { + break; + } } s->deckLink->Release(); s->deckLink = nullptr; - dnum++; } deckLinkIterator->Release(); if (s->deckLink == nullptr) {