diff --git a/src/blackmagic_common.cpp b/src/blackmagic_common.cpp index 7ad68abda..a461e5f25 100644 --- a/src/blackmagic_common.cpp +++ b/src/blackmagic_common.cpp @@ -308,13 +308,27 @@ cleanup: HRESULT result = cmd;\ if (FAILED(result)) {;\ LOG(LOG_LEVEL_ERROR) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\ - ret = false;\ + ret = {};\ goto cleanup;\ }\ } while (0) #define RELEASE_IF_NOT_NULL(x) if (x != nullptr) { x->Release(); x = nullptr; } +static BMDProfileID GetDeckLinkProfileID(IDeckLinkProfile* profile) +{ + IDeckLinkProfileAttributes* profileAttributes = nullptr; + if (HRESULT result = profile->QueryInterface(IID_IDeckLinkProfileAttributes, (void**)&profileAttributes); FAILED(result)) { + return {}; + } + + int64_t profileIDInt = 0; + // Get Profile ID attribute + profileAttributes->GetInt(BMDDeckLinkProfileID, &profileIDInt); + profileAttributes->Release(); + return (BMDProfileID) profileIDInt; +} + class ProfileCallback : public IDeckLinkProfileCallback { public: @@ -322,7 +336,7 @@ class ProfileCallback : public IDeckLinkProfileCallback m_requestedProfile->AddRef(); } - HRESULT ProfileChanging (/* in */ [[maybe_unused]] IDeckLinkProfile* profileToBeActivated, /* in */ [[maybe_unused]] BOOL streamsWillBeForcedToStop) override { return S_OK; } + HRESULT ProfileChanging (/* in */ [[maybe_unused]] IDeckLinkProfile* profileToBeActivated, /* in */ [[maybe_unused]] BMD_BOOL streamsWillBeForcedToStop) override { return S_OK; } HRESULT ProfileActivated (/* in */ [[maybe_unused]] IDeckLinkProfile* activatedProfile) override { std::lock_guard lock(m_profileActivatedMutex); { @@ -434,6 +448,50 @@ cleanup: return ret; } +static BMDProfileID decklink_get_active_profile_id(IDeckLink *decklink) +{ + BMDProfileID ret{}; + IDeckLinkProfileManager *manager = nullptr; + + if (HRESULT result = decklink->QueryInterface(IID_IDeckLinkProfileManager, (void**)&manager); FAILED(result)) { + if (result != E_NOINTERFACE) { + LOG(LOG_LEVEL_ERROR) << "Cannot get IDeckLinkProfileManager: " << bmd_hresult_to_string(result) << "\n"; + } + return {}; + } + + IDeckLinkProfileIterator *it = nullptr; + IDeckLinkProfile *profile = nullptr; + EXIT_IF_FAILED(manager->GetProfiles(&it), "Cannot get profiles iterator"); + while (it->Next(&profile) == S_OK) { + BMD_BOOL isActiveProfile = BMD_FALSE; + if ((profile->IsActive(&isActiveProfile) == S_OK) && isActiveProfile) { + ret = GetDeckLinkProfileID(profile); + profile->Release(); + break; + } + profile->Release(); + } + +cleanup: + RELEASE_IF_NOT_NULL(it); + RELEASE_IF_NOT_NULL(manager); + return ret; +} + +bool bmd_check_stereo_profile(IDeckLink *deckLink) { + if (BMDProfileID profile_active = decklink_get_active_profile_id(deckLink)) { + if (profile_active != bmdProfileOneSubDeviceHalfDuplex && + profile_active != bmdProfileOneSubDeviceFullDuplex) { + uint32_t profile_fcc_host = ntohl(profile_active); + log_msg(LOG_LEVEL_ERROR, MOD_NAME "Active profile '%.4s' may not be compatible with stereo mode.\n", (char *) &profile_fcc_host); + log_msg(LOG_LEVEL_INFO, MOD_NAME "Use 'profile=' parameter to set 1-subdevice mode in either '1dhd' (half) or '1dfd' (full) duplex.\n"); + } + return false; + } + return true; +} + string bmd_get_device_name(IDeckLink *decklink) { BMD_STR deviceNameString = NULL; char * deviceNameCString = NULL; diff --git a/src/blackmagic_common.hpp b/src/blackmagic_common.hpp index 68ed7ca5a..f94a48dff 100644 --- a/src/blackmagic_common.hpp +++ b/src/blackmagic_common.hpp @@ -104,6 +104,7 @@ void decklink_uninitialize(); bool blackmagic_api_version_check(); void print_decklink_version(void); +bool bmd_check_stereo_profile(IDeckLink *deckLink); bool decklink_set_duplex(IDeckLink *decklink, uint32_t profileID); std::string bmd_get_device_name(IDeckLink *decklink); std::string bmd_get_audio_connection_name(BMDAudioOutputAnalogAESSwitch audioConnection); diff --git a/src/video_capture/decklink.cpp b/src/video_capture/decklink.cpp index 7f9d43306..aa7aab8f2 100644 --- a/src/video_capture/decklink.cpp +++ b/src/video_capture/decklink.cpp @@ -142,6 +142,7 @@ struct device_state { bool audio = false; /* wheather we process audio or not */ struct tile *tile = nullptr; bool init(struct vidcap_decklink_state *s, struct tile *tile, BMDAudioConnection audioConnection); + void check_attributes(struct vidcap_decklink_state *s); }; struct vidcap_decklink_state { @@ -1062,6 +1063,13 @@ static bool decklink_cap_configure_audio(struct vidcap_decklink_state *s, unsign return true; } +void device_state::check_attributes(struct vidcap_decklink_state *s) +{ + if (s->stereo) { + bmd_check_stereo_profile(deckLink); + } +} + #define INIT_ERR() do { RELEASE_IF_NOT_NULL(displayMode); RELEASE_IF_NOT_NULL(displayModeIterator); return false; } while (0) bool device_state::init(struct vidcap_decklink_state *s, struct tile *t, BMDAudioConnection audioConnection) { @@ -1153,6 +1161,8 @@ bool device_state::init(struct vidcap_decklink_state *s, struct tile *t, BMDAudi BMD_CHECK(deckLinkInput->GetDisplayModeIterator(&displayModeIterator), "Could not obtain the video input display mode iterator:", INIT_ERR()); + check_attributes(s); + int mnum = 0; #define MODE_SPEC_AUTODETECT -1 #define MODE_SPEC_FOURCC -2 diff --git a/src/video_display/decklink.cpp b/src/video_display/decklink.cpp index 1ded736dc..08bb1749a 100644 --- a/src/video_display/decklink.cpp +++ b/src/video_display/decklink.cpp @@ -750,6 +750,7 @@ display_decklink_reconfigure_video(void *state, struct video_desc desc) } if (s->stereo) { + bmd_check_stereo_profile(s->state.at(0).deckLink); if ((int) desc.tile_count != 2) { log_msg(LOG_LEVEL_ERROR, MOD_NAME "In stereo mode exactly " "2 streams expected, %d received.\n", desc.tile_count);