Input optional
This commit is contained in:
@@ -252,6 +252,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
if (pOpenGLComposite->Start())
|
||||
break; // success
|
||||
MessageBoxA(NULL, "The OpenGL/DeckLink runtime initialized, but playout failed to start. See the previous DeckLink start message for the failing call.", "Startup failed", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxA(NULL, "The OpenGL/DeckLink runtime failed to initialize. See the previous initialization message for the failing call.", "Startup failed", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
// Failed to initialize - cleanup
|
||||
|
||||
@@ -466,6 +466,7 @@ bool OpenGLComposite::InitDeckLink()
|
||||
BMDDisplayMode outputDisplayMode = bmdModeHD1080p5994;
|
||||
std::string inputDisplayModeName = "1080p59.94";
|
||||
std::string outputDisplayModeName = "1080p59.94";
|
||||
std::string initFailureReason;
|
||||
int outputFrameRowBytes;
|
||||
HRESULT result;
|
||||
|
||||
@@ -550,8 +551,8 @@ bool OpenGLComposite::InitDeckLink()
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use a full duplex device as capture and playback, or half-duplex device
|
||||
// as capture or playback.
|
||||
// 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 (!mDLInput && pDL->QueryInterface(IID_IDeckLinkInput, (void**)&mDLInput) == S_OK)
|
||||
inputUsed = true;
|
||||
@@ -575,26 +576,29 @@ bool OpenGLComposite::InitDeckLink()
|
||||
break;
|
||||
}
|
||||
|
||||
if (! mDLOutput || ! mDLInput)
|
||||
if (!mDLOutput)
|
||||
{
|
||||
MessageBox(NULL, _T("Expected both Input and Output DeckLink devices"), _T("This application requires two DeckLink devices."), MB_OK);
|
||||
MessageBox(NULL, _T("Expected an Output DeckLink device"), _T("This application requires a DeckLink output device."), MB_OK);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mDLInput->GetDisplayModeIterator(&pDLInputDisplayModeIterator) != S_OK)
|
||||
if (mDLInput && mDLInput->GetDisplayModeIterator(&pDLInputDisplayModeIterator) != S_OK)
|
||||
{
|
||||
MessageBox(NULL, _T("Cannot get input Display Mode Iterator."), _T("DeckLink error."), MB_OK);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!FindDeckLinkDisplayMode(pDLInputDisplayModeIterator, inputDisplayMode, &pDLInputDisplayMode))
|
||||
if (mDLInput && !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;
|
||||
}
|
||||
pDLInputDisplayModeIterator->Release();
|
||||
pDLInputDisplayModeIterator = NULL;
|
||||
if (pDLInputDisplayModeIterator)
|
||||
{
|
||||
pDLInputDisplayModeIterator->Release();
|
||||
pDLInputDisplayModeIterator = NULL;
|
||||
}
|
||||
|
||||
if (mDLOutput->GetDisplayModeIterator(&pDLOutputDisplayModeIterator) != S_OK)
|
||||
{
|
||||
@@ -611,13 +615,18 @@ bool OpenGLComposite::InitDeckLink()
|
||||
pDLOutputDisplayModeIterator->Release();
|
||||
pDLOutputDisplayModeIterator = NULL;
|
||||
|
||||
mInputFrameWidth = pDLInputDisplayMode->GetWidth();
|
||||
mInputFrameHeight = pDLInputDisplayMode->GetHeight();
|
||||
mOutputFrameWidth = pDLOutputDisplayMode->GetWidth();
|
||||
mOutputFrameHeight = pDLOutputDisplayMode->GetHeight();
|
||||
mInputFrameWidth = pDLInputDisplayMode ? pDLInputDisplayMode->GetWidth() : mOutputFrameWidth;
|
||||
mInputFrameHeight = pDLInputDisplayMode ? pDLInputDisplayMode->GetHeight() : mOutputFrameHeight;
|
||||
if (!mDLInput)
|
||||
mInputDisplayModeName = "No input - black frame";
|
||||
|
||||
if (! CheckOpenGLExtensions())
|
||||
{
|
||||
initFailureReason = "OpenGL extension checks failed.";
|
||||
goto error;
|
||||
}
|
||||
if (mInputFrameWidth != mOutputFrameWidth || mInputFrameHeight != mOutputFrameHeight)
|
||||
{
|
||||
mFastTransferExtensionAvailable = false;
|
||||
@@ -625,7 +634,10 @@ bool OpenGLComposite::InitDeckLink()
|
||||
}
|
||||
|
||||
if (! InitOpenGLState())
|
||||
{
|
||||
initFailureReason = "OpenGL state initialization failed.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mRuntimeHost)
|
||||
{
|
||||
@@ -660,26 +672,51 @@ bool OpenGLComposite::InitDeckLink()
|
||||
}
|
||||
}
|
||||
|
||||
if (mDLInput)
|
||||
{
|
||||
// Use custom allocators so we pin only once then recycle them
|
||||
CComPtr<IDeckLinkVideoBufferAllocatorProvider> captureAllocator(new (std::nothrow) InputAllocatorPool(hGLDC, hGLRC));
|
||||
|
||||
if (mDLInput->EnableVideoInputWithAllocatorProvider(inputDisplayMode, bmdFormat8BitYUV, bmdVideoInputFlagDefault, captureAllocator) != S_OK)
|
||||
goto error;
|
||||
{
|
||||
OutputDebugStringA("DeckLink input could not be enabled; continuing in output-only black-frame mode.\n");
|
||||
mDLInput->Release();
|
||||
mDLInput = NULL;
|
||||
mHasNoInputSource = true;
|
||||
mInputDisplayModeName = "No input - black frame";
|
||||
if (mRuntimeHost)
|
||||
mRuntimeHost->SetSignalStatus(false, mInputFrameWidth, mInputFrameHeight, mInputDisplayModeName);
|
||||
}
|
||||
}
|
||||
|
||||
mCaptureDelegate = new CaptureDelegate(this);
|
||||
if (mDLInput->SetCallback(mCaptureDelegate) != S_OK)
|
||||
goto error;
|
||||
if (mDLInput)
|
||||
{
|
||||
mCaptureDelegate = new CaptureDelegate(this);
|
||||
if (mDLInput->SetCallback(mCaptureDelegate) != S_OK)
|
||||
{
|
||||
initFailureReason = "DeckLink input setup failed while installing the capture callback.";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (mRuntimeHost)
|
||||
{
|
||||
mRuntimeHost->SetSignalStatus(false, mInputFrameWidth, mInputFrameHeight, mInputDisplayModeName);
|
||||
}
|
||||
|
||||
if (mDLOutput->RowBytesForPixelFormat(bmdFormat8BitBGRA, mOutputFrameWidth, &outputFrameRowBytes) != S_OK)
|
||||
{
|
||||
initFailureReason = "DeckLink output setup failed while calculating BGRA row bytes.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Use a custom allocator so we pin only once then recycle them
|
||||
mPlayoutAllocator = new PinnedMemoryAllocator(hGLDC, hGLRC, VideoFrameTransfer::GPUtoCPU, 1, outputFrameRowBytes * mOutputFrameHeight);
|
||||
|
||||
if (mDLOutput->EnableVideoOutput(outputDisplayMode, bmdVideoOutputFlagDefault) != S_OK)
|
||||
{
|
||||
initFailureReason = "DeckLink output setup failed while enabling video output.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mDLOutput->QueryInterface(IID_IDeckLinkKeyer, (void**)&mDLKeyer) == S_OK && mDLKeyer != NULL)
|
||||
mDeckLinkKeyerInterfaceAvailable = true;
|
||||
@@ -734,26 +771,41 @@ bool OpenGLComposite::InitDeckLink()
|
||||
IDeckLinkVideoBuffer* outputFrameBuffer = NULL;
|
||||
|
||||
if (mPlayoutAllocator->AllocateVideoBuffer(&outputFrameBuffer) != S_OK)
|
||||
{
|
||||
initFailureReason = "DeckLink output setup failed while allocating an output frame buffer.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mDLOutput->CreateVideoFrameWithBuffer(mOutputFrameWidth, mOutputFrameHeight, outputFrameRowBytes, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, outputFrameBuffer, &outputFrame) != S_OK)
|
||||
{
|
||||
initFailureReason = "DeckLink output setup failed while creating an output video frame.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
mDLOutputVideoFrameQueue.push_back(outputFrame);
|
||||
}
|
||||
|
||||
mPlayoutDelegate = new PlayoutDelegate(this);
|
||||
if (mPlayoutDelegate == NULL)
|
||||
{
|
||||
initFailureReason = "DeckLink output setup failed while creating the playout callback.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mDLOutput->SetScheduledFrameCompletionCallback(mPlayoutDelegate) != S_OK)
|
||||
{
|
||||
initFailureReason = "DeckLink output setup failed while installing the scheduled-frame callback.";
|
||||
goto error;
|
||||
}
|
||||
|
||||
bSuccess = true;
|
||||
|
||||
error:
|
||||
if (!bSuccess)
|
||||
{
|
||||
if (!initFailureReason.empty())
|
||||
MessageBoxA(NULL, initFailureReason.c_str(), "DeckLink initialization failed", MB_OK | MB_ICONERROR);
|
||||
|
||||
if (mDLKeyer != NULL)
|
||||
{
|
||||
mDLKeyer->Disable();
|
||||
@@ -1195,7 +1247,8 @@ void OpenGLComposite::PlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame,
|
||||
if (mFastTransferExtensionAvailable)
|
||||
{
|
||||
// Finished with mCaptureTexture
|
||||
VideoFrameTransfer::endTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||
if (!mHasNoInputSource)
|
||||
VideoFrameTransfer::endTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||
|
||||
if (! mPlayoutAllocator->transferFrame(pFrame, mOutputTexture))
|
||||
OutputDebugStringA("Playback: transferFrame() failed\n");
|
||||
@@ -1232,6 +1285,16 @@ void OpenGLComposite::PlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame,
|
||||
bool OpenGLComposite::Start()
|
||||
{
|
||||
mTotalPlayoutFrames = 0;
|
||||
if (!mDLOutput)
|
||||
{
|
||||
MessageBoxA(NULL, "Cannot start playout because no DeckLink output device is available.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
if (mDLOutputVideoFrameQueue.empty())
|
||||
{
|
||||
MessageBoxA(NULL, "Cannot start playout because the output frame queue is empty.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preroll frames
|
||||
for (unsigned i = 0; i < kPrerollFrameCount; i++)
|
||||
@@ -1244,11 +1307,15 @@ bool OpenGLComposite::Start()
|
||||
// Start with a black frame for playout
|
||||
IDeckLinkVideoBuffer* outputVideoFrameBuffer;
|
||||
if (outputVideoFrame->QueryInterface(IID_IDeckLinkVideoBuffer, (void**)&outputVideoFrameBuffer) != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not query the preroll output frame buffer.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outputVideoFrameBuffer->StartAccess(bmdBufferAccessWrite) != S_OK)
|
||||
{
|
||||
outputVideoFrameBuffer->Release();
|
||||
MessageBoxA(NULL, "Could not write to the preroll output frame buffer.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1260,13 +1327,27 @@ bool OpenGLComposite::Start()
|
||||
outputVideoFrameBuffer->Release();
|
||||
|
||||
if (mDLOutput->ScheduleVideoFrame(outputVideoFrame, (mTotalPlayoutFrames * mFrameDuration), mFrameDuration, mFrameTimescale) != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not schedule a preroll output frame.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
mTotalPlayoutFrames++;
|
||||
}
|
||||
|
||||
mDLInput->StartStreams();
|
||||
mDLOutput->StartScheduledPlayback(0, mFrameTimescale, 1.0);
|
||||
if (mDLInput)
|
||||
{
|
||||
if (mDLInput->StartStreams() != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not start the DeckLink input stream.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mDLOutput->StartScheduledPlayback(0, mFrameTimescale, 1.0) != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not start DeckLink scheduled playback.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1296,11 +1377,17 @@ bool OpenGLComposite::Stop()
|
||||
}
|
||||
}
|
||||
|
||||
mDLInput->StopStreams();
|
||||
mDLInput->DisableVideoInput();
|
||||
if (mDLInput)
|
||||
{
|
||||
mDLInput->StopStreams();
|
||||
mDLInput->DisableVideoInput();
|
||||
}
|
||||
|
||||
mDLOutput->StopScheduledPlayback(0, NULL, 0);
|
||||
mDLOutput->DisableVideoOutput();
|
||||
if (mDLOutput)
|
||||
{
|
||||
mDLOutput->StopScheduledPlayback(0, NULL, 0);
|
||||
mDLOutput->DisableVideoOutput();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1920,10 +2007,8 @@ void OpenGLComposite::renderEffect()
|
||||
{
|
||||
PollRuntimeChanges();
|
||||
|
||||
if (mHasNoInputSource)
|
||||
return;
|
||||
|
||||
if (mFastTransferExtensionAvailable)
|
||||
const bool hasInputSource = !mHasNoInputSource;
|
||||
if (hasInputSource && mFastTransferExtensionAvailable)
|
||||
{
|
||||
// Signal that we're about to draw using mCaptureTexture onto mFBOTexture.
|
||||
VideoFrameTransfer::beginTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||
@@ -1931,7 +2016,17 @@ void OpenGLComposite::renderEffect()
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
renderDecodePass();
|
||||
if (hasInputSource)
|
||||
{
|
||||
renderDecodePass();
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mDecodeFrameBuf);
|
||||
glViewport(0, 0, mInputFrameWidth, mInputFrameHeight);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
const std::vector<RuntimeRenderState> layerStates = mRuntimeHost ? mRuntimeHost->GetLayerRenderStates(mInputFrameWidth, mInputFrameHeight) : std::vector<RuntimeRenderState>();
|
||||
if (layerStates.empty() || mLayerPrograms.empty())
|
||||
@@ -1963,7 +2058,7 @@ void OpenGLComposite::renderEffect()
|
||||
|
||||
pushFramebufferToHistoryRing(mDecodeFrameBuf, mSourceHistoryRing);
|
||||
|
||||
if (mFastTransferExtensionAvailable)
|
||||
if (hasInputSource && mFastTransferExtensionAvailable)
|
||||
VideoFrameTransfer::endTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user