From 35f5a024fdbea50456b74cde43312d884272d626 Mon Sep 17 00:00:00 2001 From: Aiden Date: Wed, 6 May 2026 10:44:55 +1000 Subject: [PATCH] Decklink helper --- .../decklink/DeckLinkSession.cpp | 287 ++++++++++++++ .../decklink/DeckLinkSession.h | 3 + .../gl/OpenGLComposite.cpp | 356 ++---------------- .../gl/OpenGLComposite.h | 1 + 4 files changed, 329 insertions(+), 318 deletions(-) diff --git a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp index 890bf0b..07e7de3 100644 --- a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp @@ -1,8 +1,32 @@ #include "DeckLinkSession.h" +#include "DeckLinkDisplayMode.h" #include "GlRenderConstants.h" +#include +#include #include +#include +#include + +namespace +{ +std::string BstrToUtf8(BSTR value) +{ + if (value == NULL) + return std::string(); + + const int requiredBytes = WideCharToMultiByte(CP_UTF8, 0, value, -1, NULL, 0, NULL, NULL); + if (requiredBytes <= 1) + return std::string(); + + std::vector utf8Name(static_cast(requiredBytes), '\0'); + if (WideCharToMultiByte(CP_UTF8, 0, value, -1, utf8Name.data(), requiredBytes, NULL, NULL) <= 0) + return std::string(); + + return std::string(utf8Name.data()); +} +} DeckLinkSession::~DeckLinkSession() { @@ -57,6 +81,269 @@ void DeckLinkSession::ReleaseResources() } } +bool DeckLinkSession::DiscoverDevicesAndModes(BMDDisplayMode inputDisplayMode, BMDDisplayMode outputDisplayMode, const std::string& requestedInputDisplayModeName, const std::string& requestedOutputDisplayModeName, std::string& error) +{ + bool success = false; + IDeckLinkIterator* deckLinkIterator = NULL; + IDeckLink* deckLink = NULL; + IDeckLinkProfileAttributes* deckLinkAttributes = NULL; + IDeckLinkDisplayModeIterator* inputDisplayModeIterator = NULL; + IDeckLinkDisplayModeIterator* outputDisplayModeIterator = NULL; + IDeckLinkDisplayMode* inputMode = NULL; + IDeckLinkDisplayMode* outputMode = NULL; + + inputDisplayModeName = requestedInputDisplayModeName; + outputDisplayModeName = requestedOutputDisplayModeName; + + HRESULT result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&deckLinkIterator); + if (FAILED(result)) + { + error = "Please install the Blackmagic DeckLink drivers to use the features of this application."; + return false; + } + + while (deckLinkIterator->Next(&deckLink) == S_OK) + { + int64_t duplexMode; + bool deviceSupportsInternalKeying = false; + bool deviceSupportsExternalKeying = false; + std::string modelName; + + if (deckLink->QueryInterface(IID_IDeckLinkProfileAttributes, (void**)&deckLinkAttributes) != S_OK) + { + printf("Could not obtain the IDeckLinkProfileAttributes interface\n"); + deckLink->Release(); + deckLink = NULL; + continue; + } + + result = deckLinkAttributes->GetInt(BMDDeckLinkDuplex, &duplexMode); + BOOL attributeFlag = FALSE; + if (deckLinkAttributes->GetFlag(BMDDeckLinkSupportsInternalKeying, &attributeFlag) == S_OK) + deviceSupportsInternalKeying = (attributeFlag != FALSE); + attributeFlag = FALSE; + if (deckLinkAttributes->GetFlag(BMDDeckLinkSupportsExternalKeying, &attributeFlag) == S_OK) + deviceSupportsExternalKeying = (attributeFlag != FALSE); + BSTR modelNameBstr = NULL; + if (deckLinkAttributes->GetString(BMDDeckLinkModelName, &modelNameBstr) == S_OK) + { + modelName = BstrToUtf8(modelNameBstr); + if (modelNameBstr != NULL) + SysFreeString(modelNameBstr); + } + deckLinkAttributes->Release(); + deckLinkAttributes = NULL; + + if (result != S_OK || duplexMode == bmdDuplexInactive) + { + deckLink->Release(); + deckLink = NULL; + continue; + } + + bool inputUsed = false; + if (!input && deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&input) == S_OK) + inputUsed = true; + + if (!output && (!inputUsed || (duplexMode == bmdDuplexFull))) + { + if (deckLink->QueryInterface(IID_IDeckLinkOutput, (void**)&output) != S_OK) + output = NULL; + else + { + outputModelName = modelName; + supportsInternalKeying = deviceSupportsInternalKeying; + supportsExternalKeying = deviceSupportsExternalKeying; + } + } + + deckLink->Release(); + deckLink = NULL; + + if (output && input) + break; + } + + if (!output) + { + error = "Expected an Output DeckLink device"; + goto cleanup; + } + + if (input && input->GetDisplayModeIterator(&inputDisplayModeIterator) != S_OK) + { + error = "Cannot get input Display Mode Iterator."; + goto cleanup; + } + + if (input && !FindDeckLinkDisplayMode(inputDisplayModeIterator, inputDisplayMode, &inputMode)) + { + error = "Cannot get specified input BMDDisplayMode for configured mode: " + requestedInputDisplayModeName; + goto cleanup; + } + if (inputDisplayModeIterator) + { + inputDisplayModeIterator->Release(); + inputDisplayModeIterator = NULL; + } + + if (output->GetDisplayModeIterator(&outputDisplayModeIterator) != S_OK) + { + error = "Cannot get output Display Mode Iterator."; + goto cleanup; + } + + if (!FindDeckLinkDisplayMode(outputDisplayModeIterator, outputDisplayMode, &outputMode)) + { + error = "Cannot get specified output BMDDisplayMode for configured mode: " + requestedOutputDisplayModeName; + goto cleanup; + } + outputDisplayModeIterator->Release(); + outputDisplayModeIterator = NULL; + + outputFrameWidth = outputMode->GetWidth(); + outputFrameHeight = outputMode->GetHeight(); + inputFrameWidth = inputMode ? inputMode->GetWidth() : outputFrameWidth; + inputFrameHeight = inputMode ? inputMode->GetHeight() : outputFrameHeight; + if (!input) + inputDisplayModeName = "No input - black frame"; + outputMode->GetFrameRate(&frameDuration, &frameTimescale); + + success = true; + +cleanup: + if (!success) + ReleaseResources(); + if (deckLink != NULL) + deckLink->Release(); + if (deckLinkAttributes != NULL) + deckLinkAttributes->Release(); + if (inputMode != NULL) + inputMode->Release(); + if (outputMode != NULL) + outputMode->Release(); + if (inputDisplayModeIterator != NULL) + inputDisplayModeIterator->Release(); + if (outputDisplayModeIterator != NULL) + outputDisplayModeIterator->Release(); + if (deckLinkIterator != NULL) + deckLinkIterator->Release(); + return success; +} + +bool DeckLinkSession::ConfigureInput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, BMDDisplayMode inputDisplayMode, std::string& error) +{ + if (!input) + { + hasNoInputSource = true; + inputDisplayModeName = "No input - black frame"; + return true; + } + + CComPtr captureAllocator(new (std::nothrow) InputAllocatorPool(hdc, hglrc)); + + if (input->EnableVideoInputWithAllocatorProvider(inputDisplayMode, bmdFormat8BitYUV, bmdVideoInputFlagDefault, captureAllocator) != S_OK) + { + OutputDebugStringA("DeckLink input could not be enabled; continuing in output-only black-frame mode.\n"); + input->Release(); + input = NULL; + hasNoInputSource = true; + inputDisplayModeName = "No input - black frame"; + return true; + } + + captureDelegate = new CaptureDelegate(owner); + if (input->SetCallback(captureDelegate) != S_OK) + { + error = "DeckLink input setup failed while installing the capture callback."; + return false; + } + + return true; +} + +bool DeckLinkSession::ConfigureOutput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, BMDDisplayMode outputDisplayMode, bool externalKeyingEnabled, std::string& error) +{ + int outputFrameRowBytes = 0; + if (output->RowBytesForPixelFormat(bmdFormat8BitBGRA, outputFrameWidth, &outputFrameRowBytes) != S_OK) + { + error = "DeckLink output setup failed while calculating BGRA row bytes."; + return false; + } + + playoutAllocator = new PinnedMemoryAllocator(hdc, hglrc, VideoFrameTransfer::GPUtoCPU, 1, outputFrameRowBytes * outputFrameHeight); + + if (output->EnableVideoOutput(outputDisplayMode, bmdVideoOutputFlagDefault) != S_OK) + { + error = "DeckLink output setup failed while enabling video output."; + return false; + } + + if (output->QueryInterface(IID_IDeckLinkKeyer, (void**)&keyer) == S_OK && keyer != NULL) + keyerInterfaceAvailable = true; + + if (externalKeyingEnabled) + { + if (!supportsExternalKeying) + { + statusMessage = "External keying was requested, but the selected DeckLink output does not report external keying support."; + } + else if (!keyerInterfaceAvailable) + { + statusMessage = "External keying was requested, but the selected DeckLink output does not expose the IDeckLinkKeyer interface."; + } + else if (keyer->Enable(TRUE) != S_OK || keyer->SetLevel(255) != S_OK) + { + statusMessage = "External keying was requested, but enabling the DeckLink keyer failed."; + } + else + { + externalKeyingActive = true; + statusMessage = "External keying is active on the selected DeckLink output."; + } + } + else if (supportsExternalKeying) + { + statusMessage = "Selected DeckLink output supports external keying. Set enableExternalKeying to true in runtime-host.json to request it."; + } + + for (int i = 0; i < 10; i++) + { + IDeckLinkMutableVideoFrame* outputFrame = NULL; + IDeckLinkVideoBuffer* outputFrameBuffer = NULL; + + if (playoutAllocator->AllocateVideoBuffer(&outputFrameBuffer) != S_OK) + { + error = "DeckLink output setup failed while allocating an output frame buffer."; + return false; + } + + if (output->CreateVideoFrameWithBuffer(outputFrameWidth, outputFrameHeight, outputFrameRowBytes, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, outputFrameBuffer, &outputFrame) != S_OK) + { + error = "DeckLink output setup failed while creating an output video frame."; + outputFrameBuffer->Release(); + return false; + } + + outputVideoFrameQueue.push_back(outputFrame); + } + + playoutDelegate = new PlayoutDelegate(owner); + if (playoutDelegate == NULL) + { + error = "DeckLink output setup failed while creating the playout callback."; + return false; + } + + if (output->SetScheduledFrameCompletionCallback(playoutDelegate) != S_OK) + { + error = "DeckLink output setup failed while installing the scheduled-frame callback."; + return false; + } + + return true; +} + bool DeckLinkSession::Start(unsigned outputHeight) { totalPlayoutFrames = 0; diff --git a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h index 1706bde..e9fee12 100644 --- a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h +++ b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h @@ -15,6 +15,9 @@ public: ~DeckLinkSession(); void ReleaseResources(); + bool DiscoverDevicesAndModes(BMDDisplayMode inputDisplayMode, BMDDisplayMode outputDisplayMode, const std::string& requestedInputDisplayModeName, const std::string& requestedOutputDisplayModeName, std::string& error); + bool ConfigureInput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, BMDDisplayMode inputDisplayMode, std::string& error); + bool ConfigureOutput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, BMDDisplayMode outputDisplayMode, bool externalKeyingEnabled, std::string& error); bool Start(unsigned outputFrameHeight); bool Stop(); diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp index d98dda4..c5d528b 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp @@ -81,21 +81,11 @@ OpenGLComposite::~OpenGLComposite() bool OpenGLComposite::InitDeckLink() { - bool bSuccess = false; - IDeckLinkIterator* pDLIterator = NULL; - IDeckLink* pDL = NULL; - IDeckLinkProfileAttributes* deckLinkAttributes = NULL; - IDeckLinkDisplayModeIterator* pDLInputDisplayModeIterator = NULL; - IDeckLinkDisplayModeIterator* pDLOutputDisplayModeIterator = NULL; - IDeckLinkDisplayMode* pDLInputDisplayMode = NULL; - IDeckLinkDisplayMode* pDLOutputDisplayMode = NULL; BMDDisplayMode inputDisplayMode = bmdModeHD1080p5994; BMDDisplayMode outputDisplayMode = bmdModeHD1080p5994; std::string inputDisplayModeName = "1080p59.94"; std::string outputDisplayModeName = "1080p59.94"; std::string initFailureReason; - int outputFrameRowBytes; - HRESULT result; if (mRuntimeHost && mRuntimeHost->GetRepoRoot().empty()) { @@ -124,131 +114,16 @@ bool OpenGLComposite::InitDeckLink() return false; } } - mDeckLink->inputDisplayModeName = inputDisplayModeName; - mDeckLink->outputDisplayModeName = outputDisplayModeName; - result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&pDLIterator); - if (FAILED(result)) + if (!mDeckLink->DiscoverDevicesAndModes(inputDisplayMode, outputDisplayMode, inputDisplayModeName, outputDisplayModeName, initFailureReason)) { - MessageBox(NULL, _T("Please install the Blackmagic DeckLink drivers to use the features of this application."), _T("This application requires the DeckLink drivers installed."), MB_OK); + const char* title = initFailureReason == "Please install the Blackmagic DeckLink drivers to use the features of this application." + ? "This application requires the DeckLink drivers installed." + : "DeckLink initialization failed"; + MessageBoxA(NULL, initFailureReason.c_str(), title, MB_OK | MB_ICONERROR); return false; } - while (pDLIterator->Next(&pDL) == S_OK) - { - int64_t duplexMode; - bool supportsInternalKeying = false; - bool supportsExternalKeying = false; - std::string modelName; - - if (result = pDL->QueryInterface(IID_IDeckLinkProfileAttributes, (void**)&deckLinkAttributes) != S_OK) - { - printf("Could not obtain the IDeckLinkProfileAttributes interface - result %08x\n", result); - pDL->Release(); - pDL = NULL; - continue; - } - - result = deckLinkAttributes->GetInt(BMDDeckLinkDuplex, &duplexMode); - BOOL attributeFlag = FALSE; - if (deckLinkAttributes->GetFlag(BMDDeckLinkSupportsInternalKeying, &attributeFlag) == S_OK) - supportsInternalKeying = (attributeFlag != FALSE); - attributeFlag = FALSE; - if (deckLinkAttributes->GetFlag(BMDDeckLinkSupportsExternalKeying, &attributeFlag) == S_OK) - supportsExternalKeying = (attributeFlag != FALSE); - BSTR modelNameBstr = NULL; - if (deckLinkAttributes->GetString(BMDDeckLinkModelName, &modelNameBstr) == S_OK && modelNameBstr != NULL) - { - const int requiredBytes = WideCharToMultiByte(CP_UTF8, 0, modelNameBstr, -1, NULL, 0, NULL, NULL); - if (requiredBytes > 1) - { - std::vector utf8Name(static_cast(requiredBytes), '\0'); - if (WideCharToMultiByte(CP_UTF8, 0, modelNameBstr, -1, utf8Name.data(), requiredBytes, NULL, NULL) > 0) - modelName.assign(utf8Name.data()); - } - SysFreeString(modelNameBstr); - } - deckLinkAttributes->Release(); - deckLinkAttributes = NULL; - - if (result != S_OK || duplexMode == bmdDuplexInactive) - { - pDL->Release(); - pDL = NULL; - continue; - } - - // Preserve the original input-then-output selection for half-duplex cards. - // Input is optional later, but choosing output first can pick the wrong card. - bool inputUsed = false; - if (!mDeckLink->input && pDL->QueryInterface(IID_IDeckLinkInput, (void**)&mDeckLink->input) == S_OK) - inputUsed = true; - - if (!mDeckLink->output && (!inputUsed || (duplexMode == bmdDuplexFull))) - { - if (pDL->QueryInterface(IID_IDeckLinkOutput, (void**)&mDeckLink->output) != S_OK) - mDeckLink->output = NULL; - else - { - mDeckLink->outputModelName = modelName; - mDeckLink->supportsInternalKeying = supportsInternalKeying; - mDeckLink->supportsExternalKeying = supportsExternalKeying; - } - } - - pDL->Release(); - pDL = NULL; - - if (mDeckLink->output && mDeckLink->input) - break; - } - - if (!mDeckLink->output) - { - MessageBox(NULL, _T("Expected an Output DeckLink device"), _T("This application requires a DeckLink output device."), MB_OK); - goto error; - } - - if (mDeckLink->input && mDeckLink->input->GetDisplayModeIterator(&pDLInputDisplayModeIterator) != S_OK) - { - MessageBox(NULL, _T("Cannot get input Display Mode Iterator."), _T("DeckLink error."), MB_OK); - goto error; - } - - if (mDeckLink->input && !FindDeckLinkDisplayMode(pDLInputDisplayModeIterator, inputDisplayMode, &pDLInputDisplayMode)) - { - const std::string error = "Cannot get specified input BMDDisplayMode for configured mode: " + inputDisplayModeName; - MessageBoxA(NULL, error.c_str(), "DeckLink input error.", MB_OK); - goto error; - } - if (pDLInputDisplayModeIterator) - { - pDLInputDisplayModeIterator->Release(); - pDLInputDisplayModeIterator = NULL; - } - - if (mDeckLink->output->GetDisplayModeIterator(&pDLOutputDisplayModeIterator) != S_OK) - { - MessageBox(NULL, _T("Cannot get output Display Mode Iterator."), _T("DeckLink error."), MB_OK); - goto error; - } - - if (!FindDeckLinkDisplayMode(pDLOutputDisplayModeIterator, outputDisplayMode, &pDLOutputDisplayMode)) - { - const std::string error = "Cannot get specified output BMDDisplayMode for configured mode: " + outputDisplayModeName; - MessageBoxA(NULL, error.c_str(), "DeckLink output error.", MB_OK); - goto error; - } - pDLOutputDisplayModeIterator->Release(); - pDLOutputDisplayModeIterator = NULL; - - mDeckLink->outputFrameWidth = pDLOutputDisplayMode->GetWidth(); - mDeckLink->outputFrameHeight = pDLOutputDisplayMode->GetHeight(); - mDeckLink->inputFrameWidth = pDLInputDisplayMode ? pDLInputDisplayMode->GetWidth() : mDeckLink->outputFrameWidth; - mDeckLink->inputFrameHeight = pDLInputDisplayMode ? pDLInputDisplayMode->GetHeight() : mDeckLink->outputFrameHeight; - if (!mDeckLink->input) - mDeckLink->inputDisplayModeName = "No input - black frame"; - if (! CheckOpenGLExtensions()) { initFailureReason = "OpenGL extension checks failed."; @@ -266,22 +141,9 @@ bool OpenGLComposite::InitDeckLink() goto error; } - if (mRuntimeHost) - { - mDeckLink->statusMessage = mDeckLink->outputModelName.empty() - ? "DeckLink output device selected." - : ("Selected output device: " + mDeckLink->outputModelName); - mRuntimeHost->SetDeckLinkOutputStatus( - mDeckLink->outputModelName, - mDeckLink->supportsInternalKeying, - mDeckLink->supportsExternalKeying, - mDeckLink->keyerInterfaceAvailable, - mRuntimeHost->ExternalKeyingEnabled(), - mDeckLink->externalKeyingActive, - mDeckLink->statusMessage); - } - - pDLOutputDisplayMode->GetFrameRate(&mDeckLink->frameDuration, &mDeckLink->frameTimescale); + PublishDeckLinkOutputStatus(mDeckLink->outputModelName.empty() + ? "DeckLink output device selected." + : ("Selected output device: " + mDeckLink->outputModelName)); // Resize window to match output video frame, but scale large formats down by half for viewing. if (mDeckLink->outputFrameWidth < 1920) @@ -299,180 +161,29 @@ bool OpenGLComposite::InitDeckLink() } } - if (mDeckLink->input) + if (!mDeckLink->ConfigureInput(this, hGLDC, hGLRC, inputDisplayMode, initFailureReason)) { - // Use custom allocators so we pin only once then recycle them - CComPtr captureAllocator(new (std::nothrow) InputAllocatorPool(hGLDC, hGLRC)); - - if (mDeckLink->input->EnableVideoInputWithAllocatorProvider(inputDisplayMode, bmdFormat8BitYUV, bmdVideoInputFlagDefault, captureAllocator) != S_OK) - { - OutputDebugStringA("DeckLink input could not be enabled; continuing in output-only black-frame mode.\n"); - mDeckLink->input->Release(); - mDeckLink->input = NULL; - mDeckLink->hasNoInputSource = true; - mDeckLink->inputDisplayModeName = "No input - black frame"; - if (mRuntimeHost) - mRuntimeHost->SetSignalStatus(false, mDeckLink->inputFrameWidth, mDeckLink->inputFrameHeight, mDeckLink->inputDisplayModeName); - } + goto error; } - - if (mDeckLink->input) - { - mDeckLink->captureDelegate = new CaptureDelegate(this); - if (mDeckLink->input->SetCallback(mDeckLink->captureDelegate) != S_OK) - { - initFailureReason = "DeckLink input setup failed while installing the capture callback."; - goto error; - } - } - else if (mRuntimeHost) + if (!mDeckLink->input && mRuntimeHost) { mRuntimeHost->SetSignalStatus(false, mDeckLink->inputFrameWidth, mDeckLink->inputFrameHeight, mDeckLink->inputDisplayModeName); } - if (mDeckLink->output->RowBytesForPixelFormat(bmdFormat8BitBGRA, mDeckLink->outputFrameWidth, &outputFrameRowBytes) != S_OK) + if (!mDeckLink->ConfigureOutput(this, hGLDC, hGLRC, outputDisplayMode, mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled(), initFailureReason)) { - initFailureReason = "DeckLink output setup failed while calculating BGRA row bytes."; goto error; } - // Use a custom allocator so we pin only once then recycle them - mDeckLink->playoutAllocator = new PinnedMemoryAllocator(hGLDC, hGLRC, VideoFrameTransfer::GPUtoCPU, 1, outputFrameRowBytes * mDeckLink->outputFrameHeight); + PublishDeckLinkOutputStatus(mDeckLink->statusMessage); - if (mDeckLink->output->EnableVideoOutput(outputDisplayMode, bmdVideoOutputFlagDefault) != S_OK) - { - initFailureReason = "DeckLink output setup failed while enabling video output."; - goto error; - } - - if (mDeckLink->output->QueryInterface(IID_IDeckLinkKeyer, (void**)&mDeckLink->keyer) == S_OK && mDeckLink->keyer != NULL) - mDeckLink->keyerInterfaceAvailable = true; - - if (mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled()) - { - if (!mDeckLink->supportsExternalKeying) - { - mDeckLink->statusMessage = "External keying was requested, but the selected DeckLink output does not report external keying support."; - } - else if (!mDeckLink->keyerInterfaceAvailable) - { - mDeckLink->statusMessage = "External keying was requested, but the selected DeckLink output does not expose the IDeckLinkKeyer interface."; - } - else if (mDeckLink->keyer->Enable(TRUE) != S_OK || mDeckLink->keyer->SetLevel(255) != S_OK) - { - mDeckLink->statusMessage = "External keying was requested, but enabling the DeckLink keyer failed."; - } - else - { - mDeckLink->externalKeyingActive = true; - mDeckLink->statusMessage = "External keying is active on the selected DeckLink output."; - } - } - else if (mDeckLink->supportsExternalKeying) - { - mDeckLink->statusMessage = "Selected DeckLink output supports external keying. Set enableExternalKeying to true in runtime-host.json to request it."; - } - - if (mRuntimeHost) - { - mRuntimeHost->SetDeckLinkOutputStatus( - mDeckLink->outputModelName, - mDeckLink->supportsInternalKeying, - mDeckLink->supportsExternalKeying, - mDeckLink->keyerInterfaceAvailable, - mRuntimeHost->ExternalKeyingEnabled(), - mDeckLink->externalKeyingActive, - mDeckLink->statusMessage); - } - - // Create a queue of 10 IDeckLinkMutableVideoFrame objects to use for scheduling output video frames. - // The ScheduledFrameCompleted() callback will immediately schedule a new frame using the next video frame from this queue. - for (int i = 0; i < 10; i++) - { - // The frame read back from the GPU frame buffer and used for the playout video frame is in BGRA format. - // The BGRA frame will be converted on playout to YCbCr either in hardware on most DeckLink cards or in software - // within the DeckLink API for DeckLink devices without this hardware conversion. - // If you want RGB 4:4:4 format to be played out "over the wire" in SDI, turn on the "Use 4:4:4 SDI" in the control - // panel or turn on the bmdDeckLinkConfig444SDIVideoOutput flag using the IDeckLinkConfiguration interface. - IDeckLinkMutableVideoFrame* outputFrame; - IDeckLinkVideoBuffer* outputFrameBuffer = NULL; - - if (mDeckLink->playoutAllocator->AllocateVideoBuffer(&outputFrameBuffer) != S_OK) - { - initFailureReason = "DeckLink output setup failed while allocating an output frame buffer."; - goto error; - } - - if (mDeckLink->output->CreateVideoFrameWithBuffer(mDeckLink->outputFrameWidth, mDeckLink->outputFrameHeight, outputFrameRowBytes, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, outputFrameBuffer, &outputFrame) != S_OK) - { - initFailureReason = "DeckLink output setup failed while creating an output video frame."; - goto error; - } - - mDeckLink->outputVideoFrameQueue.push_back(outputFrame); - } - - mDeckLink->playoutDelegate = new PlayoutDelegate(this); - if (mDeckLink->playoutDelegate == NULL) - { - initFailureReason = "DeckLink output setup failed while creating the playout callback."; - goto error; - } - - if (mDeckLink->output->SetScheduledFrameCompletionCallback(mDeckLink->playoutDelegate) != S_OK) - { - initFailureReason = "DeckLink output setup failed while installing the scheduled-frame callback."; - goto error; - } - - bSuccess = true; + return true; error: - if (!bSuccess) - { - if (!initFailureReason.empty()) - MessageBoxA(NULL, initFailureReason.c_str(), "DeckLink initialization failed", MB_OK | MB_ICONERROR); - - mDeckLink->ReleaseResources(); - } - - if (pDL != NULL) - { - pDL->Release(); - pDL = NULL; - } - - if (pDLInputDisplayMode != NULL) - { - pDLInputDisplayMode->Release(); - pDLInputDisplayMode = NULL; - } - - if (pDLOutputDisplayMode != NULL) - { - pDLOutputDisplayMode->Release(); - pDLOutputDisplayMode = NULL; - } - - if (pDLInputDisplayModeIterator != NULL) - { - pDLInputDisplayModeIterator->Release(); - pDLInputDisplayModeIterator = NULL; - } - - if (pDLOutputDisplayModeIterator != NULL) - { - pDLOutputDisplayModeIterator->Release(); - pDLOutputDisplayModeIterator = NULL; - } - - if (pDLIterator != NULL) - { - pDLIterator->Release(); - pDLIterator = NULL; - } - - return bSuccess; + if (!initFailureReason.empty()) + MessageBoxA(NULL, initFailureReason.c_str(), "DeckLink initialization failed", MB_OK | MB_ICONERROR); + mDeckLink->ReleaseResources(); + return false; } void OpenGLComposite::paintGL() @@ -504,6 +215,24 @@ void OpenGLComposite::resizeWindow(int width, int height) } } +void OpenGLComposite::PublishDeckLinkOutputStatus(const std::string& statusMessage) +{ + if (!mRuntimeHost) + return; + + if (!statusMessage.empty()) + mDeckLink->statusMessage = statusMessage; + + mRuntimeHost->SetDeckLinkOutputStatus( + mDeckLink->outputModelName, + mDeckLink->supportsInternalKeying, + mDeckLink->supportsExternalKeying, + mDeckLink->keyerInterfaceAvailable, + mRuntimeHost->ExternalKeyingEnabled(), + mDeckLink->externalKeyingActive, + mDeckLink->statusMessage); +} + bool OpenGLComposite::InitOpenGLState() { if (! ResolveGLExtensions()) @@ -717,17 +446,8 @@ bool OpenGLComposite::Stop() const bool wasExternalKeyingActive = mDeckLink->externalKeyingActive; mDeckLink->Stop(); - if (wasExternalKeyingActive && mRuntimeHost) - { - mRuntimeHost->SetDeckLinkOutputStatus( - mDeckLink->outputModelName, - mDeckLink->supportsInternalKeying, - mDeckLink->supportsExternalKeying, - mDeckLink->keyerInterfaceAvailable, - mRuntimeHost->ExternalKeyingEnabled(), - mDeckLink->externalKeyingActive, - "External keying has been disabled."); - } + if (wasExternalKeyingActive) + PublishDeckLinkOutputStatus("External keying has been disabled."); return true; } diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.h b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.h index 9aab710..5fbeff7 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.h +++ b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.h @@ -105,6 +105,7 @@ public: private: void resizeWindow(int width, int height); bool CheckOpenGLExtensions(); + void PublishDeckLinkOutputStatus(const std::string& statusMessage); using LayerProgram = OpenGLRenderer::LayerProgram; HWND hGLWnd;