diff --git a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.cpp b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.cpp index b0b219a..85bf5ea 100644 --- a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.cpp @@ -14,6 +14,17 @@ std::string NormalizeModeToken(const std::string& value) } bool ResolveConfiguredDisplayMode(const std::string& videoFormat, const std::string& frameRate, BMDDisplayMode& displayMode, std::string& displayModeName) +{ + VideoFormat videoMode; + if (!ResolveConfiguredVideoFormat(videoFormat, frameRate, videoMode)) + return false; + + displayMode = videoMode.displayMode; + displayModeName = videoMode.displayName; + return true; +} + +bool ResolveConfiguredVideoFormat(const std::string& videoFormat, const std::string& frameRate, VideoFormat& videoMode) { const std::string formatToken = NormalizeModeToken(videoFormat); const std::string frameToken = NormalizeModeToken(frameRate); @@ -78,8 +89,8 @@ bool ResolveConfiguredDisplayMode(const std::string& videoFormat, const std::str { if (combinedToken == option.token || (frameToken.empty() && formatToken == option.token)) { - displayMode = option.mode; - displayModeName = option.displayName; + videoMode.displayMode = option.mode; + videoMode.displayName = option.displayName; return true; } } @@ -87,6 +98,31 @@ bool ResolveConfiguredDisplayMode(const std::string& videoFormat, const std::str return false; } +bool ResolveConfiguredVideoFormats( + const std::string& inputVideoFormat, + const std::string& inputFrameRate, + const std::string& outputVideoFormat, + const std::string& outputFrameRate, + VideoFormatSelection& videoModes, + std::string& error) +{ + if (!ResolveConfiguredVideoFormat(inputVideoFormat, inputFrameRate, videoModes.input)) + { + error = "Unsupported DeckLink inputVideoFormat/inputFrameRate in config/runtime-host.json: " + + inputVideoFormat + " / " + inputFrameRate; + return false; + } + + if (!ResolveConfiguredVideoFormat(outputVideoFormat, outputFrameRate, videoModes.output)) + { + error = "Unsupported DeckLink outputVideoFormat/outputFrameRate in config/runtime-host.json: " + + outputVideoFormat + " / " + outputFrameRate; + return false; + } + + return true; +} + bool FindDeckLinkDisplayMode(IDeckLinkDisplayModeIterator* iterator, BMDDisplayMode targetMode, IDeckLinkDisplayMode** foundMode) { if (!iterator || !foundMode) diff --git a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.h b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.h index 3896f4b..3be24fd 100644 --- a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.h +++ b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkDisplayMode.h @@ -4,6 +4,44 @@ #include +struct FrameSize +{ + unsigned width = 0; + unsigned height = 0; + + bool IsEmpty() const { return width == 0 || height == 0; } +}; + +inline bool operator==(const FrameSize& left, const FrameSize& right) +{ + return left.width == right.width && left.height == right.height; +} + +inline bool operator!=(const FrameSize& left, const FrameSize& right) +{ + return !(left == right); +} + +struct VideoFormat +{ + BMDDisplayMode displayMode = bmdModeHD1080p5994; + std::string displayName = "1080p59.94"; +}; + +struct VideoFormatSelection +{ + VideoFormat input; + VideoFormat output; +}; + std::string NormalizeModeToken(const std::string& value); bool ResolveConfiguredDisplayMode(const std::string& videoFormat, const std::string& frameRate, BMDDisplayMode& displayMode, std::string& displayModeName); +bool ResolveConfiguredVideoFormat(const std::string& videoFormat, const std::string& frameRate, VideoFormat& videoMode); +bool ResolveConfiguredVideoFormats( + const std::string& inputVideoFormat, + const std::string& inputFrameRate, + const std::string& outputVideoFormat, + const std::string& outputFrameRate, + VideoFormatSelection& videoModes, + std::string& error); bool FindDeckLinkDisplayMode(IDeckLinkDisplayModeIterator* iterator, BMDDisplayMode targetMode, IDeckLinkDisplayMode** foundMode); diff --git a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp index 87b1a3a..5a7084b 100644 --- a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.cpp @@ -1,6 +1,5 @@ #include "DeckLinkSession.h" -#include "DeckLinkDisplayMode.h" #include "GlRenderConstants.h" #include @@ -57,14 +56,14 @@ void DeckLinkSession::ReleaseResources() playoutAllocator.Release(); } -bool DeckLinkSession::DiscoverDevicesAndModes(BMDDisplayMode inputDisplayMode, BMDDisplayMode outputDisplayMode, const std::string& requestedInputDisplayModeName, const std::string& requestedOutputDisplayModeName, std::string& error) +bool DeckLinkSession::DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error) { CComPtr deckLinkIterator; CComPtr inputMode; CComPtr outputMode; - inputDisplayModeName = requestedInputDisplayModeName; - outputDisplayModeName = requestedOutputDisplayModeName; + inputDisplayModeName = videoModes.input.displayName; + outputDisplayModeName = videoModes.output.displayName; HRESULT result = CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, reinterpret_cast(&deckLinkIterator)); if (FAILED(result)) @@ -143,9 +142,9 @@ bool DeckLinkSession::DiscoverDevicesAndModes(BMDDisplayMode inputDisplayMode, B return false; } - if (input && !FindDeckLinkDisplayMode(inputDisplayModeIterator, inputDisplayMode, &inputMode)) + if (input && !FindDeckLinkDisplayMode(inputDisplayModeIterator, videoModes.input.displayMode, &inputMode)) { - error = "Cannot get specified input BMDDisplayMode for configured mode: " + requestedInputDisplayModeName; + error = "Cannot get specified input BMDDisplayMode for configured mode: " + videoModes.input.displayName; ReleaseResources(); return false; } @@ -159,17 +158,17 @@ bool DeckLinkSession::DiscoverDevicesAndModes(BMDDisplayMode inputDisplayMode, B return false; } - if (!FindDeckLinkDisplayMode(outputDisplayModeIterator, outputDisplayMode, &outputMode)) + if (!FindDeckLinkDisplayMode(outputDisplayModeIterator, videoModes.output.displayMode, &outputMode)) { - error = "Cannot get specified output BMDDisplayMode for configured mode: " + requestedOutputDisplayModeName; + error = "Cannot get specified output BMDDisplayMode for configured mode: " + videoModes.output.displayName; ReleaseResources(); return false; } - outputFrameWidth = outputMode->GetWidth(); - outputFrameHeight = outputMode->GetHeight(); - inputFrameWidth = inputMode ? inputMode->GetWidth() : outputFrameWidth; - inputFrameHeight = inputMode ? inputMode->GetHeight() : outputFrameHeight; + outputFrameSize = { static_cast(outputMode->GetWidth()), static_cast(outputMode->GetHeight()) }; + inputFrameSize = inputMode + ? FrameSize{ static_cast(inputMode->GetWidth()), static_cast(inputMode->GetHeight()) } + : outputFrameSize; if (!input) inputDisplayModeName = "No input - black frame"; outputMode->GetFrameRate(&frameDuration, &frameTimescale); @@ -177,7 +176,7 @@ bool DeckLinkSession::DiscoverDevicesAndModes(BMDDisplayMode inputDisplayMode, B return true; } -bool DeckLinkSession::ConfigureInput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, BMDDisplayMode inputDisplayMode, std::string& error) +bool DeckLinkSession::ConfigureInput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, const VideoFormat& inputVideoMode, std::string& error) { if (!input) { @@ -188,7 +187,7 @@ bool DeckLinkSession::ConfigureInput(OpenGLComposite* owner, HDC hdc, HGLRC hglr CComPtr captureAllocator(new (std::nothrow) InputAllocatorPool(hdc, hglrc)); - if (input->EnableVideoInputWithAllocatorProvider(inputDisplayMode, bmdFormat8BitYUV, bmdVideoInputFlagDefault, captureAllocator) != S_OK) + if (input->EnableVideoInputWithAllocatorProvider(inputVideoMode.displayMode, bmdFormat8BitYUV, bmdVideoInputFlagDefault, captureAllocator) != S_OK) { OutputDebugStringA("DeckLink input could not be enabled; continuing in output-only black-frame mode.\n"); input.Release(); @@ -212,23 +211,23 @@ bool DeckLinkSession::ConfigureInput(OpenGLComposite* owner, HDC hdc, HGLRC hglr return true; } -bool DeckLinkSession::ConfigureOutput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, BMDDisplayMode outputDisplayMode, bool externalKeyingEnabled, std::string& error) +bool DeckLinkSession::ConfigureOutput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error) { int outputFrameRowBytes = 0; - if (output->RowBytesForPixelFormat(bmdFormat8BitBGRA, outputFrameWidth, &outputFrameRowBytes) != S_OK) + if (output->RowBytesForPixelFormat(bmdFormat8BitBGRA, outputFrameSize.width, &outputFrameRowBytes) != S_OK) { error = "DeckLink output setup failed while calculating BGRA row bytes."; return false; } - playoutAllocator.Attach(new (std::nothrow) PinnedMemoryAllocator(hdc, hglrc, VideoFrameTransfer::GPUtoCPU, 1, outputFrameRowBytes * outputFrameHeight)); + playoutAllocator.Attach(new (std::nothrow) PinnedMemoryAllocator(hdc, hglrc, VideoFrameTransfer::GPUtoCPU, 1, outputFrameRowBytes * outputFrameSize.height)); if (playoutAllocator == nullptr) { error = "DeckLink output setup failed while creating the playout allocator."; return false; } - if (output->EnableVideoOutput(outputDisplayMode, bmdVideoOutputFlagDefault) != S_OK) + if (output->EnableVideoOutput(outputVideoMode.displayMode, bmdVideoOutputFlagDefault) != S_OK) { error = "DeckLink output setup failed while enabling video output."; return false; @@ -273,7 +272,7 @@ bool DeckLinkSession::ConfigureOutput(OpenGLComposite* owner, HDC hdc, HGLRC hgl return false; } - if (output->CreateVideoFrameWithBuffer(outputFrameWidth, outputFrameHeight, outputFrameRowBytes, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, outputFrameBuffer, &outputFrame) != S_OK) + if (output->CreateVideoFrameWithBuffer(outputFrameSize.width, outputFrameSize.height, outputFrameRowBytes, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, outputFrameBuffer, &outputFrame) != S_OK) { error = "DeckLink output setup failed while creating an output video frame."; return false; @@ -374,7 +373,7 @@ bool DeckLinkSession::Start() void* pFrame; outputVideoFrameBuffer->GetBytes((void**)&pFrame); - memset(pFrame, 0, outputVideoFrame->GetRowBytes() * outputFrameHeight); + memset(pFrame, 0, outputVideoFrame->GetRowBytes() * outputFrameSize.height); outputVideoFrameBuffer->EndAccess(bmdBufferAccessWrite); diff --git a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h index 1b90fb3..657d086 100644 --- a/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h +++ b/apps/LoopThroughWithOpenGLCompositing/decklink/DeckLinkSession.h @@ -1,6 +1,7 @@ #pragma once #include "DeckLinkAPI_h.h" +#include "DeckLinkDisplayMode.h" #include "DeckLinkFrameTransfer.h" #include @@ -16,20 +17,22 @@ 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 DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error); + bool ConfigureInput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, const VideoFormat& inputVideoMode, std::string& error); + bool ConfigureOutput(OpenGLComposite* owner, HDC hdc, HGLRC hglrc, const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error); bool Start(); bool Stop(); bool HasInputDevice() const { return input != nullptr; } bool HasInputSource() const { return !hasNoInputSource; } void SetInputSourceMissing(bool missing) { hasNoInputSource = missing; } - bool InputOutputDimensionsDiffer() const { return inputFrameWidth != outputFrameWidth || inputFrameHeight != outputFrameHeight; } - unsigned InputFrameWidth() const { return inputFrameWidth; } - unsigned InputFrameHeight() const { return inputFrameHeight; } - unsigned OutputFrameWidth() const { return outputFrameWidth; } - unsigned OutputFrameHeight() const { return outputFrameHeight; } + bool InputOutputDimensionsDiffer() const { return inputFrameSize != outputFrameSize; } + const FrameSize& InputFrameSize() const { return inputFrameSize; } + const FrameSize& OutputFrameSize() const { return outputFrameSize; } + unsigned InputFrameWidth() const { return inputFrameSize.width; } + unsigned InputFrameHeight() const { return inputFrameSize.height; } + unsigned OutputFrameWidth() const { return outputFrameSize.width; } + unsigned OutputFrameHeight() const { return outputFrameSize.height; } const std::string& InputDisplayModeName() const { return inputDisplayModeName; } const std::string& OutputModelName() const { return outputModelName; } bool SupportsInternalKeying() const { return supportsInternalKeying; } @@ -56,10 +59,8 @@ private: BMDTimeValue frameDuration = 0; BMDTimeScale frameTimescale = 0; unsigned totalPlayoutFrames = 0; - unsigned inputFrameWidth = 0; - unsigned inputFrameHeight = 0; - unsigned outputFrameWidth = 0; - unsigned outputFrameHeight = 0; + FrameSize inputFrameSize; + FrameSize outputFrameSize; std::string inputDisplayModeName = "1080p59.94"; std::string outputDisplayModeName = "1080p59.94"; bool hasNoInputSource = true; diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp index 1b19758..bc6b05c 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp @@ -97,10 +97,7 @@ OpenGLComposite::~OpenGLComposite() bool OpenGLComposite::InitDeckLink() { - BMDDisplayMode inputDisplayMode = bmdModeHD1080p5994; - BMDDisplayMode outputDisplayMode = bmdModeHD1080p5994; - std::string inputDisplayModeName = "1080p59.94"; - std::string outputDisplayModeName = "1080p59.94"; + VideoFormatSelection videoModes; std::string initFailureReason; if (mRuntimeHost && mRuntimeHost->GetRepoRoot().empty()) @@ -115,23 +112,20 @@ bool OpenGLComposite::InitDeckLink() if (mRuntimeHost) { - if (!ResolveConfiguredDisplayMode(mRuntimeHost->GetInputVideoFormat(), mRuntimeHost->GetInputFrameRate(), inputDisplayMode, inputDisplayModeName)) + if (!ResolveConfiguredVideoFormats( + mRuntimeHost->GetInputVideoFormat(), + mRuntimeHost->GetInputFrameRate(), + mRuntimeHost->GetOutputVideoFormat(), + mRuntimeHost->GetOutputFrameRate(), + videoModes, + initFailureReason)) { - const std::string error = "Unsupported DeckLink inputVideoFormat/inputFrameRate in config/runtime-host.json: " + - mRuntimeHost->GetInputVideoFormat() + " / " + mRuntimeHost->GetInputFrameRate(); - MessageBoxA(NULL, error.c_str(), "DeckLink input mode configuration error", MB_OK); - return false; - } - if (!ResolveConfiguredDisplayMode(mRuntimeHost->GetOutputVideoFormat(), mRuntimeHost->GetOutputFrameRate(), outputDisplayMode, outputDisplayModeName)) - { - const std::string error = "Unsupported DeckLink outputVideoFormat/outputFrameRate in config/runtime-host.json: " + - mRuntimeHost->GetOutputVideoFormat() + " / " + mRuntimeHost->GetOutputFrameRate(); - MessageBoxA(NULL, error.c_str(), "DeckLink output mode configuration error", MB_OK); + MessageBoxA(NULL, initFailureReason.c_str(), "DeckLink mode configuration error", MB_OK); return false; } } - if (!mDeckLink->DiscoverDevicesAndModes(inputDisplayMode, outputDisplayMode, inputDisplayModeName, outputDisplayModeName, initFailureReason)) + if (!mDeckLink->DiscoverDevicesAndModes(videoModes, initFailureReason)) { const char* title = initFailureReason == "Please install the Blackmagic DeckLink drivers to use the features of this application." ? "This application requires the DeckLink drivers installed." @@ -177,7 +171,7 @@ bool OpenGLComposite::InitDeckLink() } } - if (!mDeckLink->ConfigureInput(this, hGLDC, hGLRC, inputDisplayMode, initFailureReason)) + if (!mDeckLink->ConfigureInput(this, hGLDC, hGLRC, videoModes.input, initFailureReason)) { goto error; } @@ -186,7 +180,7 @@ bool OpenGLComposite::InitDeckLink() mRuntimeHost->SetSignalStatus(false, mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight(), mDeckLink->InputDisplayModeName()); } - if (!mDeckLink->ConfigureOutput(this, hGLDC, hGLRC, outputDisplayMode, mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled(), initFailureReason)) + if (!mDeckLink->ConfigureOutput(this, hGLDC, hGLRC, videoModes.output, mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled(), initFailureReason)) { goto error; }