149 lines
3.5 KiB
C++
149 lines
3.5 KiB
C++
#include "DeckLinkSession.h"
|
|
|
|
#include "GlRenderConstants.h"
|
|
|
|
#include <cstring>
|
|
|
|
DeckLinkSession::~DeckLinkSession()
|
|
{
|
|
ReleaseResources();
|
|
}
|
|
|
|
void DeckLinkSession::ReleaseResources()
|
|
{
|
|
if (input != nullptr)
|
|
{
|
|
input->SetCallback(nullptr);
|
|
if (captureDelegate != nullptr)
|
|
{
|
|
captureDelegate->Release();
|
|
captureDelegate = nullptr;
|
|
}
|
|
input->Release();
|
|
input = nullptr;
|
|
}
|
|
|
|
while (!outputVideoFrameQueue.empty())
|
|
{
|
|
IDeckLinkMutableVideoFrame* frameToRelease = outputVideoFrameQueue.front();
|
|
if (frameToRelease != nullptr)
|
|
frameToRelease->Release();
|
|
outputVideoFrameQueue.pop_front();
|
|
}
|
|
|
|
if (output != nullptr)
|
|
{
|
|
if (keyer != nullptr)
|
|
{
|
|
keyer->Disable();
|
|
keyer->Release();
|
|
keyer = nullptr;
|
|
externalKeyingActive = false;
|
|
}
|
|
output->SetScheduledFrameCompletionCallback(nullptr);
|
|
if (playoutDelegate != nullptr)
|
|
{
|
|
playoutDelegate->Release();
|
|
playoutDelegate = nullptr;
|
|
}
|
|
output->Release();
|
|
output = nullptr;
|
|
}
|
|
|
|
if (playoutAllocator != nullptr)
|
|
{
|
|
playoutAllocator->Release();
|
|
playoutAllocator = nullptr;
|
|
}
|
|
}
|
|
|
|
bool DeckLinkSession::Start(unsigned outputHeight)
|
|
{
|
|
totalPlayoutFrames = 0;
|
|
if (!output)
|
|
{
|
|
MessageBoxA(NULL, "Cannot start playout because no DeckLink output device is available.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
|
return false;
|
|
}
|
|
if (outputVideoFrameQueue.empty())
|
|
{
|
|
MessageBoxA(NULL, "Cannot start playout because the output frame queue is empty.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
|
return false;
|
|
}
|
|
|
|
for (unsigned i = 0; i < kPrerollFrameCount; i++)
|
|
{
|
|
IDeckLinkMutableVideoFrame* outputVideoFrame = outputVideoFrameQueue.front();
|
|
outputVideoFrameQueue.push_back(outputVideoFrame);
|
|
outputVideoFrameQueue.pop_front();
|
|
|
|
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;
|
|
}
|
|
|
|
void* pFrame;
|
|
outputVideoFrameBuffer->GetBytes((void**)&pFrame);
|
|
memset(pFrame, 0, outputVideoFrame->GetRowBytes() * outputHeight);
|
|
|
|
outputVideoFrameBuffer->EndAccess(bmdBufferAccessWrite);
|
|
outputVideoFrameBuffer->Release();
|
|
|
|
if (output->ScheduleVideoFrame(outputVideoFrame, (totalPlayoutFrames * frameDuration), frameDuration, frameTimescale) != S_OK)
|
|
{
|
|
MessageBoxA(NULL, "Could not schedule a preroll output frame.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
|
return false;
|
|
}
|
|
|
|
totalPlayoutFrames++;
|
|
}
|
|
|
|
if (input)
|
|
{
|
|
if (input->StartStreams() != S_OK)
|
|
{
|
|
MessageBoxA(NULL, "Could not start the DeckLink input stream.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
|
return false;
|
|
}
|
|
}
|
|
if (output->StartScheduledPlayback(0, frameTimescale, 1.0) != S_OK)
|
|
{
|
|
MessageBoxA(NULL, "Could not start DeckLink scheduled playback.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DeckLinkSession::Stop()
|
|
{
|
|
if (keyer != nullptr)
|
|
{
|
|
keyer->Disable();
|
|
externalKeyingActive = false;
|
|
}
|
|
|
|
if (input)
|
|
{
|
|
input->StopStreams();
|
|
input->DisableVideoInput();
|
|
}
|
|
|
|
if (output)
|
|
{
|
|
output->StopScheduledPlayback(0, NULL, 0);
|
|
output->DisableVideoOutput();
|
|
}
|
|
|
|
return true;
|
|
}
|