Decklink abstraction
This commit is contained in:
@@ -3,9 +3,9 @@
|
||||
#include "OpenGLComposite.h"
|
||||
#include "GLExtensions.h"
|
||||
#include "GlRenderConstants.h"
|
||||
#include "OpenGLDeckLinkBridge.h"
|
||||
#include "OpenGLRenderPass.h"
|
||||
#include "OpenGLShaderPrograms.h"
|
||||
#include "OpenGLVideoIOBridge.h"
|
||||
#include "PngScreenshotWriter.h"
|
||||
#include "RuntimeServices.h"
|
||||
#include "ShaderBuildQueue.h"
|
||||
@@ -22,15 +22,15 @@
|
||||
|
||||
OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
||||
hGLWnd(hWnd), hGLDC(hDC), hGLRC(hRC),
|
||||
mDeckLink(std::make_unique<DeckLinkSession>()),
|
||||
mVideoIO(std::make_unique<DeckLinkSession>()),
|
||||
mRenderer(std::make_unique<OpenGLRenderer>()),
|
||||
mUseCommittedLayerStates(false),
|
||||
mScreenshotRequested(false)
|
||||
{
|
||||
InitializeCriticalSection(&pMutex);
|
||||
mRuntimeHost = std::make_unique<RuntimeHost>();
|
||||
mDeckLinkBridge = std::make_unique<OpenGLDeckLinkBridge>(
|
||||
*mDeckLink,
|
||||
mVideoIOBridge = std::make_unique<OpenGLVideoIOBridge>(
|
||||
*mVideoIO,
|
||||
*mRenderer,
|
||||
*mRuntimeHost,
|
||||
pMutex,
|
||||
@@ -51,13 +51,18 @@ OpenGLComposite::~OpenGLComposite()
|
||||
mRuntimeServices->Stop();
|
||||
if (mShaderBuildQueue)
|
||||
mShaderBuildQueue->Stop();
|
||||
mDeckLink->ReleaseResources();
|
||||
mVideoIO->ReleaseResources();
|
||||
mRenderer->DestroyResources();
|
||||
|
||||
DeleteCriticalSection(&pMutex);
|
||||
}
|
||||
|
||||
bool OpenGLComposite::InitDeckLink()
|
||||
{
|
||||
return InitVideoIO();
|
||||
}
|
||||
|
||||
bool OpenGLComposite::InitVideoIO()
|
||||
{
|
||||
VideoFormatSelection videoModes;
|
||||
std::string initFailureReason;
|
||||
@@ -87,7 +92,7 @@ bool OpenGLComposite::InitDeckLink()
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDeckLink->DiscoverDevicesAndModes(videoModes, initFailureReason))
|
||||
if (!mVideoIO->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."
|
||||
@@ -95,7 +100,7 @@ bool OpenGLComposite::InitDeckLink()
|
||||
MessageBoxA(NULL, initFailureReason.c_str(), title, MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
if (!mDeckLink->SelectPreferredFormats(videoModes, initFailureReason))
|
||||
if (!mVideoIO->SelectPreferredFormats(videoModes, initFailureReason))
|
||||
goto error;
|
||||
|
||||
if (! CheckOpenGLExtensions())
|
||||
@@ -110,38 +115,38 @@ bool OpenGLComposite::InitDeckLink()
|
||||
goto error;
|
||||
}
|
||||
|
||||
PublishDeckLinkOutputStatus(mDeckLink->OutputModelName().empty()
|
||||
PublishVideoIOStatus(mVideoIO->OutputModelName().empty()
|
||||
? "DeckLink output device selected."
|
||||
: ("Selected output device: " + mDeckLink->OutputModelName()));
|
||||
: ("Selected output device: " + mVideoIO->OutputModelName()));
|
||||
|
||||
// Resize window to match output video frame, but scale large formats down by half for viewing.
|
||||
if (mDeckLink->OutputFrameWidth() < 1920)
|
||||
resizeWindow(mDeckLink->OutputFrameWidth(), mDeckLink->OutputFrameHeight());
|
||||
if (mVideoIO->OutputFrameWidth() < 1920)
|
||||
resizeWindow(mVideoIO->OutputFrameWidth(), mVideoIO->OutputFrameHeight());
|
||||
else
|
||||
resizeWindow(mDeckLink->OutputFrameWidth() / 2, mDeckLink->OutputFrameHeight() / 2);
|
||||
resizeWindow(mVideoIO->OutputFrameWidth() / 2, mVideoIO->OutputFrameHeight() / 2);
|
||||
|
||||
if (!mDeckLink->ConfigureInput(this, hGLDC, hGLRC, videoModes.input, initFailureReason))
|
||||
if (!mVideoIO->ConfigureInput([this](const VideoIOFrame& frame) { mVideoIOBridge->VideoFrameArrived(frame); }, videoModes.input, initFailureReason))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
if (!mDeckLink->HasInputDevice() && mRuntimeHost)
|
||||
if (!mVideoIO->HasInputDevice() && mRuntimeHost)
|
||||
{
|
||||
mRuntimeHost->SetSignalStatus(false, mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight(), mDeckLink->InputDisplayModeName());
|
||||
mRuntimeHost->SetSignalStatus(false, mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), mVideoIO->InputDisplayModeName());
|
||||
}
|
||||
|
||||
if (!mDeckLink->ConfigureOutput(this, hGLDC, hGLRC, videoModes.output, mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled(), initFailureReason))
|
||||
if (!mVideoIO->ConfigureOutput([this](const VideoIOCompletion& completion) { mVideoIOBridge->PlayoutFrameCompleted(completion); }, videoModes.output, mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled(), initFailureReason))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
PublishDeckLinkOutputStatus(mDeckLink->StatusMessage());
|
||||
PublishVideoIOStatus(mVideoIO->StatusMessage());
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
if (!initFailureReason.empty())
|
||||
MessageBoxA(NULL, initFailureReason.c_str(), "DeckLink initialization failed", MB_OK | MB_ICONERROR);
|
||||
mDeckLink->ReleaseResources();
|
||||
mVideoIO->ReleaseResources();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -153,7 +158,7 @@ void OpenGLComposite::paintGL()
|
||||
return;
|
||||
}
|
||||
|
||||
mRenderer->PresentToWindow(hGLDC, mDeckLink->OutputFrameWidth(), mDeckLink->OutputFrameHeight());
|
||||
mRenderer->PresentToWindow(hGLDC, mVideoIO->OutputFrameWidth(), mVideoIO->OutputFrameHeight());
|
||||
ValidateRect(hGLWnd, NULL);
|
||||
LeaveCriticalSection(&pMutex);
|
||||
}
|
||||
@@ -174,22 +179,23 @@ void OpenGLComposite::resizeWindow(int width, int height)
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLComposite::PublishDeckLinkOutputStatus(const std::string& statusMessage)
|
||||
void OpenGLComposite::PublishVideoIOStatus(const std::string& statusMessage)
|
||||
{
|
||||
if (!mRuntimeHost)
|
||||
return;
|
||||
|
||||
if (!statusMessage.empty())
|
||||
mDeckLink->SetStatusMessage(statusMessage);
|
||||
mVideoIO->SetStatusMessage(statusMessage);
|
||||
|
||||
mRuntimeHost->SetDeckLinkOutputStatus(
|
||||
mDeckLink->OutputModelName(),
|
||||
mDeckLink->SupportsInternalKeying(),
|
||||
mDeckLink->SupportsExternalKeying(),
|
||||
mDeckLink->KeyerInterfaceAvailable(),
|
||||
mRuntimeHost->SetVideoIOStatus(
|
||||
"decklink",
|
||||
mVideoIO->OutputModelName(),
|
||||
mVideoIO->SupportsInternalKeying(),
|
||||
mVideoIO->SupportsExternalKeying(),
|
||||
mVideoIO->KeyerInterfaceAvailable(),
|
||||
mRuntimeHost->ExternalKeyingEnabled(),
|
||||
mDeckLink->ExternalKeyingActive(),
|
||||
mDeckLink->StatusMessage());
|
||||
mVideoIO->ExternalKeyingActive(),
|
||||
mVideoIO->StatusMessage());
|
||||
}
|
||||
|
||||
bool OpenGLComposite::InitOpenGLState()
|
||||
@@ -223,7 +229,7 @@ bool OpenGLComposite::InitOpenGLState()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mShaderPrograms->CompileLayerPrograms(mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||
if (!mShaderPrograms->CompileLayerPrograms(mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||
{
|
||||
MessageBoxA(NULL, compilerErrorMessage, "OpenGL shader failed to load or compile", MB_OK);
|
||||
return false;
|
||||
@@ -234,12 +240,12 @@ bool OpenGLComposite::InitOpenGLState()
|
||||
|
||||
std::string rendererError;
|
||||
if (!mRenderer->InitializeResources(
|
||||
mDeckLink->InputFrameWidth(),
|
||||
mDeckLink->InputFrameHeight(),
|
||||
mDeckLink->CaptureTextureWidth(),
|
||||
mDeckLink->OutputFrameWidth(),
|
||||
mDeckLink->OutputFrameHeight(),
|
||||
mDeckLink->OutputPackTextureWidth(),
|
||||
mVideoIO->InputFrameWidth(),
|
||||
mVideoIO->InputFrameHeight(),
|
||||
mVideoIO->CaptureTextureWidth(),
|
||||
mVideoIO->OutputFrameWidth(),
|
||||
mVideoIO->OutputFrameHeight(),
|
||||
mVideoIO->OutputPackTextureWidth(),
|
||||
rendererError))
|
||||
{
|
||||
MessageBoxA(NULL, rendererError.c_str(), "OpenGL initialization error.", MB_OK);
|
||||
@@ -251,20 +257,9 @@ bool OpenGLComposite::InitOpenGLState()
|
||||
return true;
|
||||
}
|
||||
|
||||
// DeckLink delegates still target OpenGLComposite; the bridge owns the per-frame work.
|
||||
void OpenGLComposite::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame, bool hasNoInputSource)
|
||||
{
|
||||
mDeckLinkBridge->VideoFrameArrived(inputFrame, hasNoInputSource);
|
||||
}
|
||||
|
||||
void OpenGLComposite::PlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completionResult)
|
||||
{
|
||||
mDeckLinkBridge->PlayoutFrameCompleted(completedFrame, completionResult);
|
||||
}
|
||||
|
||||
bool OpenGLComposite::Start()
|
||||
{
|
||||
return mDeckLink->Start();
|
||||
return mVideoIO->Start();
|
||||
}
|
||||
|
||||
bool OpenGLComposite::Stop()
|
||||
@@ -272,10 +267,10 @@ bool OpenGLComposite::Stop()
|
||||
if (mRuntimeServices)
|
||||
mRuntimeServices->Stop();
|
||||
|
||||
const bool wasExternalKeyingActive = mDeckLink->ExternalKeyingActive();
|
||||
mDeckLink->Stop();
|
||||
const bool wasExternalKeyingActive = mVideoIO->ExternalKeyingActive();
|
||||
mVideoIO->Stop();
|
||||
if (wasExternalKeyingActive)
|
||||
PublishDeckLinkOutputStatus("External keying has been disabled.");
|
||||
PublishVideoIOStatus("External keying has been disabled.");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -303,7 +298,7 @@ void OpenGLComposite::renderEffect()
|
||||
{
|
||||
ProcessRuntimePollResults();
|
||||
|
||||
const bool hasInputSource = mDeckLink->HasInputSource();
|
||||
const bool hasInputSource = mVideoIO->HasInputSource();
|
||||
std::vector<RuntimeRenderState> layerStates;
|
||||
if (mUseCommittedLayerStates)
|
||||
{
|
||||
@@ -313,7 +308,7 @@ void OpenGLComposite::renderEffect()
|
||||
}
|
||||
else if (mRuntimeHost)
|
||||
{
|
||||
if (mRuntimeHost->TryGetLayerRenderStates(mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight(), layerStates))
|
||||
if (mRuntimeHost->TryGetLayerRenderStates(mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), layerStates))
|
||||
{
|
||||
mCachedLayerRenderStates = layerStates;
|
||||
}
|
||||
@@ -327,10 +322,10 @@ void OpenGLComposite::renderEffect()
|
||||
mRenderPass->Render(
|
||||
hasInputSource,
|
||||
layerStates,
|
||||
mDeckLink->InputFrameWidth(),
|
||||
mDeckLink->InputFrameHeight(),
|
||||
mDeckLink->CaptureTextureWidth(),
|
||||
mDeckLink->InputPixelFormat(),
|
||||
mVideoIO->InputFrameWidth(),
|
||||
mVideoIO->InputFrameHeight(),
|
||||
mVideoIO->CaptureTextureWidth(),
|
||||
mVideoIO->InputPixelFormat(),
|
||||
historyCap,
|
||||
[this](const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error) {
|
||||
return mShaderPrograms->UpdateTextBindingTexture(state, textBinding, error);
|
||||
@@ -345,8 +340,8 @@ void OpenGLComposite::ProcessScreenshotRequest()
|
||||
if (!mScreenshotRequested.exchange(false))
|
||||
return;
|
||||
|
||||
const unsigned width = mDeckLink ? mDeckLink->OutputFrameWidth() : 0;
|
||||
const unsigned height = mDeckLink ? mDeckLink->OutputFrameHeight() : 0;
|
||||
const unsigned width = mVideoIO ? mVideoIO->OutputFrameWidth() : 0;
|
||||
const unsigned height = mVideoIO ? mVideoIO->OutputFrameHeight() : 0;
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
@@ -426,7 +421,7 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
||||
return true;
|
||||
|
||||
char compilerErrorMessage[1024] = {};
|
||||
if (!mShaderPrograms->CommitPreparedLayerPrograms(readyBuild, mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||
if (!mShaderPrograms->CommitPreparedLayerPrograms(readyBuild, mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||
{
|
||||
mRuntimeHost->SetCompileStatus(false, compilerErrorMessage);
|
||||
mUseCommittedLayerStates = true;
|
||||
@@ -449,13 +444,13 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
||||
|
||||
void OpenGLComposite::RequestShaderBuild()
|
||||
{
|
||||
if (!mShaderBuildQueue || !mDeckLink)
|
||||
if (!mShaderBuildQueue || !mVideoIO)
|
||||
return;
|
||||
|
||||
mUseCommittedLayerStates = true;
|
||||
if (mRuntimeHost)
|
||||
mRuntimeHost->ClearReloadRequest();
|
||||
mShaderBuildQueue->RequestBuild(mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight());
|
||||
mShaderBuildQueue->RequestBuild(mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight());
|
||||
}
|
||||
|
||||
void OpenGLComposite::broadcastRuntimeState()
|
||||
|
||||
Reference in New Issue
Block a user