Refactor
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
#include "DeckLinkDisplayMode.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
std::string NormalizeModeToken(const std::string& value)
|
||||
{
|
||||
std::string normalized;
|
||||
for (unsigned char ch : value)
|
||||
{
|
||||
if (std::isalnum(ch))
|
||||
normalized.push_back(static_cast<char>(std::tolower(ch)));
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
bool ResolveConfiguredDisplayMode(const std::string& videoFormat, const std::string& frameRate, BMDDisplayMode& displayMode, std::string& displayModeName)
|
||||
{
|
||||
const std::string formatToken = NormalizeModeToken(videoFormat);
|
||||
const std::string frameToken = NormalizeModeToken(frameRate);
|
||||
const std::string combinedToken = formatToken + frameToken;
|
||||
|
||||
struct ModeOption
|
||||
{
|
||||
const char* token;
|
||||
BMDDisplayMode mode;
|
||||
const char* displayName;
|
||||
};
|
||||
|
||||
static const ModeOption options[] =
|
||||
{
|
||||
{ "720p50", bmdModeHD720p50, "720p50" },
|
||||
{ "hd720p50", bmdModeHD720p50, "720p50" },
|
||||
{ "720p5994", bmdModeHD720p5994, "720p59.94" },
|
||||
{ "hd720p5994", bmdModeHD720p5994, "720p59.94" },
|
||||
{ "720p60", bmdModeHD720p60, "720p60" },
|
||||
{ "hd720p60", bmdModeHD720p60, "720p60" },
|
||||
{ "1080i50", bmdModeHD1080i50, "1080i50" },
|
||||
{ "hd1080i50", bmdModeHD1080i50, "1080i50" },
|
||||
{ "1080i5994", bmdModeHD1080i5994, "1080i59.94" },
|
||||
{ "hd1080i5994", bmdModeHD1080i5994, "1080i59.94" },
|
||||
{ "1080i60", bmdModeHD1080i6000, "1080i60" },
|
||||
{ "hd1080i60", bmdModeHD1080i6000, "1080i60" },
|
||||
{ "1080p2398", bmdModeHD1080p2398, "1080p23.98" },
|
||||
{ "hd1080p2398", bmdModeHD1080p2398, "1080p23.98" },
|
||||
{ "1080p24", bmdModeHD1080p24, "1080p24" },
|
||||
{ "hd1080p24", bmdModeHD1080p24, "1080p24" },
|
||||
{ "1080p25", bmdModeHD1080p25, "1080p25" },
|
||||
{ "hd1080p25", bmdModeHD1080p25, "1080p25" },
|
||||
{ "1080p2997", bmdModeHD1080p2997, "1080p29.97" },
|
||||
{ "hd1080p2997", bmdModeHD1080p2997, "1080p29.97" },
|
||||
{ "1080p30", bmdModeHD1080p30, "1080p30" },
|
||||
{ "hd1080p30", bmdModeHD1080p30, "1080p30" },
|
||||
{ "1080p50", bmdModeHD1080p50, "1080p50" },
|
||||
{ "hd1080p50", bmdModeHD1080p50, "1080p50" },
|
||||
{ "1080p5994", bmdModeHD1080p5994, "1080p59.94" },
|
||||
{ "hd1080p5994", bmdModeHD1080p5994, "1080p59.94" },
|
||||
{ "1080p60", bmdModeHD1080p6000, "1080p60" },
|
||||
{ "hd1080p60", bmdModeHD1080p6000, "1080p60" },
|
||||
{ "2160p2398", bmdMode4K2160p2398, "2160p23.98" },
|
||||
{ "4k2160p2398", bmdMode4K2160p2398, "2160p23.98" },
|
||||
{ "2160p24", bmdMode4K2160p24, "2160p24" },
|
||||
{ "4k2160p24", bmdMode4K2160p24, "2160p24" },
|
||||
{ "2160p25", bmdMode4K2160p25, "2160p25" },
|
||||
{ "4k2160p25", bmdMode4K2160p25, "2160p25" },
|
||||
{ "2160p2997", bmdMode4K2160p2997, "2160p29.97" },
|
||||
{ "4k2160p2997", bmdMode4K2160p2997, "2160p29.97" },
|
||||
{ "2160p30", bmdMode4K2160p30, "2160p30" },
|
||||
{ "4k2160p30", bmdMode4K2160p30, "2160p30" },
|
||||
{ "2160p50", bmdMode4K2160p50, "2160p50" },
|
||||
{ "4k2160p50", bmdMode4K2160p50, "2160p50" },
|
||||
{ "2160p5994", bmdMode4K2160p5994, "2160p59.94" },
|
||||
{ "4k2160p5994", bmdMode4K2160p5994, "2160p59.94" },
|
||||
{ "2160p60", bmdMode4K2160p60, "2160p60" },
|
||||
{ "4k2160p60", bmdMode4K2160p60, "2160p60" }
|
||||
};
|
||||
|
||||
for (const ModeOption& option : options)
|
||||
{
|
||||
if (combinedToken == option.token || (frameToken.empty() && formatToken == option.token))
|
||||
{
|
||||
displayMode = option.mode;
|
||||
displayModeName = option.displayName;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FindDeckLinkDisplayMode(IDeckLinkDisplayModeIterator* iterator, BMDDisplayMode targetMode, IDeckLinkDisplayMode** foundMode)
|
||||
{
|
||||
if (!iterator || !foundMode)
|
||||
return false;
|
||||
|
||||
*foundMode = NULL;
|
||||
IDeckLinkDisplayMode* candidate = NULL;
|
||||
while (iterator->Next(&candidate) == S_OK)
|
||||
{
|
||||
if (candidate->GetDisplayMode() == targetMode)
|
||||
{
|
||||
*foundMode = candidate;
|
||||
return true;
|
||||
}
|
||||
|
||||
candidate->Release();
|
||||
candidate = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "DeckLinkAPI_h.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string NormalizeModeToken(const std::string& value);
|
||||
bool ResolveConfiguredDisplayMode(const std::string& videoFormat, const std::string& frameRate, BMDDisplayMode& displayMode, std::string& displayModeName);
|
||||
bool FindDeckLinkDisplayMode(IDeckLinkDisplayModeIterator* iterator, BMDDisplayMode targetMode, IDeckLinkDisplayMode** foundMode);
|
||||
@@ -0,0 +1,409 @@
|
||||
#include "DeckLinkFrameTransfer.h"
|
||||
|
||||
#include "OpenGLComposite.h"
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
DEFINE_GUID(IID_PinnedMemoryAllocator,
|
||||
0xddf921a6, 0x279d, 0x4dcd, 0x86, 0x26, 0x75, 0x7f, 0x58, 0xa8, 0xc4, 0x35);
|
||||
|
||||
////////////////////////////////////////////
|
||||
// PinnedMemoryAllocator
|
||||
////////////////////////////////////////////
|
||||
|
||||
// PinnedMemoryAllocator implements the IDeckLinkVideoBufferAllocator interface to be used instead of the
|
||||
// built-in buffer allocator.
|
||||
//
|
||||
// For this sample application a custom buffer allocator is used to ensure each address
|
||||
// of buffer memory is aligned on a 4kB boundary required by the OpenGL pinned memory extension.
|
||||
// If the pinned memory extension is not available, this allocator will still be used and
|
||||
// demonstrates how to cache buffer allocations for efficiency.
|
||||
//
|
||||
// The frame cache delays the releasing of buffers until the cache fills up, thereby avoiding an
|
||||
// allocate plus pin operation for every frame, followed by an unpin and deallocate on every frame.
|
||||
PinnedMemoryAllocator::PinnedMemoryAllocator(HDC hdc, HGLRC hglrc, VideoFrameTransfer::Direction direction, unsigned cacheSize, unsigned bufferSize) :
|
||||
mHGLDC(hdc),
|
||||
mHGLRC(hglrc),
|
||||
mRefCount(1),
|
||||
mDirection(direction),
|
||||
mBufferSize(bufferSize),
|
||||
mFrameCacheSize(cacheSize)
|
||||
{
|
||||
}
|
||||
|
||||
PinnedMemoryAllocator::~PinnedMemoryAllocator()
|
||||
{
|
||||
// Cleanup any unused buffers that remain in the cache
|
||||
while (!mFrameCache.empty())
|
||||
{
|
||||
unPinAddress(mFrameCache.back());
|
||||
VirtualFree(mFrameCache.back(), 0, MEM_RELEASE);
|
||||
mFrameCache.pop_back();
|
||||
}
|
||||
|
||||
for (auto iter = mFrameTransfer.begin(); iter != mFrameTransfer.end(); ++iter)
|
||||
delete iter->second;
|
||||
mFrameTransfer.clear();
|
||||
}
|
||||
|
||||
bool PinnedMemoryAllocator::transferFrame(void* address, GLuint gpuTexture)
|
||||
{
|
||||
if (mFrameTransfer.count(address) == 0)
|
||||
{
|
||||
// VideoFrameTransfer prepares and pins address
|
||||
mFrameTransfer[address] = new VideoFrameTransfer(mBufferSize, address, mDirection);
|
||||
}
|
||||
|
||||
return mFrameTransfer[address]->performFrameTransfer();
|
||||
}
|
||||
|
||||
void PinnedMemoryAllocator::waitForTransferComplete(void* address)
|
||||
{
|
||||
if (mFrameTransfer.count(address))
|
||||
mFrameTransfer[address]->waitForTransferComplete();
|
||||
}
|
||||
|
||||
void PinnedMemoryAllocator::unPinAddress(void* address)
|
||||
{
|
||||
// un-pin address only if it has been pinned for transfer
|
||||
if (mFrameTransfer.count(address) > 0)
|
||||
{
|
||||
wglMakeCurrent(mHGLDC, mHGLRC);
|
||||
mFrameTransfer.erase(address);
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID iid, LPVOID* ppv)
|
||||
{
|
||||
if (!ppv)
|
||||
return E_POINTER;
|
||||
|
||||
if (iid == IID_IUnknown || iid == IID_PinnedMemoryAllocator)
|
||||
{
|
||||
*ppv = this;
|
||||
}
|
||||
else if (iid == IID_IDeckLinkVideoBufferAllocator)
|
||||
{
|
||||
*ppv = static_cast<IDeckLinkVideoBufferAllocator*>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void)
|
||||
{
|
||||
return ++mRefCount;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void)
|
||||
{
|
||||
int newCount = --mRefCount;
|
||||
if (newCount == 0)
|
||||
delete this;
|
||||
return newCount;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::AllocateVideoBuffer(IDeckLinkVideoBuffer** allocatedBuffer)
|
||||
{
|
||||
std::shared_ptr<void> sharedMemBuffer;
|
||||
|
||||
// Manage caching of allocated buffers via shared_ptr deleter.
|
||||
auto deleter = [this](void* buffer) mutable {
|
||||
if (mFrameCache.size() < mFrameCacheSize)
|
||||
{
|
||||
mFrameCache.push_back(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No room left in cache, so un-pin (if it was pinned) and free this buffer
|
||||
unPinAddress(buffer);
|
||||
VirtualFree(buffer, 0, MEM_RELEASE);
|
||||
}
|
||||
// We AddRef this class once the deleter is used because this class owns the mem
|
||||
Release();
|
||||
};
|
||||
|
||||
if (mFrameCache.empty())
|
||||
{
|
||||
// Allocate memory on a page boundary
|
||||
void* memBuffer = VirtualAlloc(NULL, mBufferSize, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE);
|
||||
if (!memBuffer)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
sharedMemBuffer = std::shared_ptr<void>(memBuffer, deleter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Re-use most recently released address
|
||||
sharedMemBuffer = std::shared_ptr<void>(mFrameCache.back(), deleter);
|
||||
mFrameCache.pop_back();
|
||||
}
|
||||
|
||||
// This class owns the mem so the buffer we return needs to AddRef() this, and Release() in the deleter
|
||||
AddRef();
|
||||
|
||||
*allocatedBuffer = new DeckLinkVideoBuffer(sharedMemBuffer, this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// InputAllocatorPool Class
|
||||
////////////////////////////////////////////
|
||||
InputAllocatorPool::InputAllocatorPool(HDC hdc, HGLRC hglrc)
|
||||
{
|
||||
mHDC = hdc;
|
||||
mHGLRC = hglrc;
|
||||
}
|
||||
|
||||
HRESULT InputAllocatorPool::QueryInterface(REFIID iid, void** ppv)
|
||||
{
|
||||
if (!ppv)
|
||||
return E_POINTER;
|
||||
|
||||
if (iid == IID_IUnknown)
|
||||
{
|
||||
*ppv = this;
|
||||
}
|
||||
else if (iid == IID_IDeckLinkVideoBufferAllocatorProvider)
|
||||
{
|
||||
*ppv = static_cast<IDeckLinkVideoBufferAllocatorProvider*>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG InputAllocatorPool::AddRef(void)
|
||||
{
|
||||
return ++mRefCount;
|
||||
}
|
||||
|
||||
ULONG InputAllocatorPool::Release(void)
|
||||
{
|
||||
int newCount = --mRefCount;
|
||||
if (newCount == 0)
|
||||
delete this;
|
||||
return newCount;
|
||||
}
|
||||
|
||||
HRESULT InputAllocatorPool::GetVideoBufferAllocator(
|
||||
/* [in] */ unsigned int bufferSize,
|
||||
/* [in] */ unsigned int,
|
||||
/* [in] */ unsigned int,
|
||||
/* [in] */ unsigned int,
|
||||
/* [in] */ BMDPixelFormat,
|
||||
/* [out] */ IDeckLinkVideoBufferAllocator** allocator)
|
||||
{
|
||||
if (!allocator)
|
||||
return E_POINTER;
|
||||
|
||||
auto existing = mAllocatorBySize.find(bufferSize);
|
||||
if (existing != mAllocatorBySize.end())
|
||||
{
|
||||
*allocator = &*existing->second;
|
||||
(*allocator)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CComPtr<PinnedMemoryAllocator> newAllocator;
|
||||
newAllocator.Attach(new (std::nothrow) PinnedMemoryAllocator(mHDC, mHGLRC, VideoFrameTransfer::CPUtoGPU, 3, bufferSize));
|
||||
if (!newAllocator)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
mAllocatorBySize.emplace(std::make_pair(bufferSize, newAllocator));
|
||||
*allocator = newAllocator.Detach();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// DeckLink Video Buffer Class
|
||||
////////////////////////////////////////////
|
||||
DeckLinkVideoBuffer::DeckLinkVideoBuffer(std::shared_ptr<void>& buffer, PinnedMemoryAllocator* parent) :
|
||||
mParentAllocator(parent),
|
||||
mRefCount(1),
|
||||
mBuffer(buffer)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeckLinkVideoBuffer::QueryInterface(REFIID riid, void** ppvObject)
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
if (riid == IID_IUnknown)
|
||||
{
|
||||
*ppvObject = this;
|
||||
AddRef();
|
||||
}
|
||||
else if (riid == IID_IDeckLinkVideoBuffer)
|
||||
{
|
||||
*ppvObject = static_cast<IDeckLinkVideoBuffer*>(this);
|
||||
AddRef();
|
||||
}
|
||||
else if (riid == IID_PinnedMemoryAllocator)
|
||||
{
|
||||
result = mParentAllocator->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppvObject = nullptr;
|
||||
result = E_NOINTERFACE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DeckLinkVideoBuffer::AddRef()
|
||||
{
|
||||
return ++mRefCount;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DeckLinkVideoBuffer::Release()
|
||||
{
|
||||
int newValue = --mRefCount;
|
||||
if (newValue == 0)
|
||||
delete this;
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeckLinkVideoBuffer::GetBytes(void** buffer)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*buffer = mBuffer.get();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeckLinkVideoBuffer::GetSize(uint64_t* size)
|
||||
{
|
||||
if (size == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*size = mParentAllocator->bufferSize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeckLinkVideoBuffer::StartAccess(BMDBufferAccessFlags)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DeckLinkVideoBuffer::EndAccess(BMDBufferAccessFlags)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// DeckLink Capture Delegate Class
|
||||
////////////////////////////////////////////
|
||||
CaptureDelegate::CaptureDelegate(OpenGLComposite* pOwner) :
|
||||
m_pOwner(pOwner),
|
||||
mRefCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT CaptureDelegate::QueryInterface(REFIID, LPVOID* ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG CaptureDelegate::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&mRefCount);
|
||||
}
|
||||
|
||||
ULONG CaptureDelegate::Release()
|
||||
{
|
||||
int newCount = InterlockedDecrement(&mRefCount);
|
||||
if (newCount == 0)
|
||||
delete this;
|
||||
return newCount;
|
||||
}
|
||||
|
||||
HRESULT CaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* inputFrame, IDeckLinkAudioInputPacket*)
|
||||
{
|
||||
if (!inputFrame)
|
||||
{
|
||||
// It's possible to receive a NULL inputFrame, but a valid audioPacket. Ignore audio-only frame.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool hasNoInputSource = (inputFrame->GetFlags() & bmdFrameHasNoInputSource) == bmdFrameHasNoInputSource;
|
||||
m_pOwner->VideoFrameArrived(inputFrame, hasNoInputSource);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// DeckLink Playout Delegate Class
|
||||
////////////////////////////////////////////
|
||||
PlayoutDelegate::PlayoutDelegate(OpenGLComposite* pOwner) :
|
||||
m_pOwner(pOwner),
|
||||
mRefCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT PlayoutDelegate::QueryInterface(REFIID, LPVOID* ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG PlayoutDelegate::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&mRefCount);
|
||||
}
|
||||
|
||||
ULONG PlayoutDelegate::Release()
|
||||
{
|
||||
int newCount = InterlockedDecrement(&mRefCount);
|
||||
if (newCount == 0)
|
||||
delete this;
|
||||
return newCount;
|
||||
}
|
||||
|
||||
HRESULT PlayoutDelegate::ScheduledFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case bmdOutputFrameDisplayedLate:
|
||||
OutputDebugStringA("ScheduledFrameCompleted() frame did not complete: Frame Displayed Late\n");
|
||||
break;
|
||||
case bmdOutputFrameDropped:
|
||||
OutputDebugStringA("ScheduledFrameCompleted() frame did not complete: Frame Dropped\n");
|
||||
break;
|
||||
case bmdOutputFrameCompleted:
|
||||
case bmdOutputFrameFlushed:
|
||||
// Don't log bmdOutputFrameFlushed result since it is expected when Stop() is called
|
||||
break;
|
||||
default:
|
||||
OutputDebugStringA("ScheduledFrameCompleted() frame did not complete: Unknown error\n");
|
||||
}
|
||||
|
||||
m_pOwner->PlayoutFrameCompleted(completedFrame, result);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT PlayoutDelegate::ScheduledPlaybackHasStopped()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <gl/gl.h>
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "DeckLinkAPI_h.h"
|
||||
#include "VideoFrameTransfer.h"
|
||||
|
||||
extern "C" const IID IID_PinnedMemoryAllocator;
|
||||
|
||||
class OpenGLComposite;
|
||||
|
||||
////////////////////////////////////////////
|
||||
// PinnedMemoryAllocator
|
||||
////////////////////////////////////////////
|
||||
class PinnedMemoryAllocator : public IDeckLinkVideoBufferAllocator
|
||||
{
|
||||
public:
|
||||
PinnedMemoryAllocator(HDC hdc, HGLRC hglrc, VideoFrameTransfer::Direction direction, unsigned cacheSize, unsigned bufferSize);
|
||||
virtual ~PinnedMemoryAllocator();
|
||||
|
||||
bool transferFrame(void* address, GLuint gpuTexture);
|
||||
void waitForTransferComplete(void* address);
|
||||
unsigned bufferSize() { return mBufferSize; }
|
||||
|
||||
// IUnknown methods
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID* ppv) override;
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
|
||||
virtual ULONG STDMETHODCALLTYPE Release(void) override;
|
||||
|
||||
// IDeckLinkVideoBufferAllocator methods
|
||||
virtual HRESULT STDMETHODCALLTYPE AllocateVideoBuffer(IDeckLinkVideoBuffer** allocatedBuffer) override;
|
||||
|
||||
private:
|
||||
void unPinAddress(void* address);
|
||||
|
||||
private:
|
||||
HDC mHGLDC;
|
||||
HGLRC mHGLRC;
|
||||
std::atomic<ULONG> mRefCount;
|
||||
VideoFrameTransfer::Direction mDirection;
|
||||
std::map<void*, VideoFrameTransfer*> mFrameTransfer;
|
||||
unsigned mBufferSize;
|
||||
std::vector<void*> mFrameCache;
|
||||
unsigned mFrameCacheSize;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// InputAllocatorPool
|
||||
////////////////////////////////////////////
|
||||
class InputAllocatorPool : public IDeckLinkVideoBufferAllocatorProvider
|
||||
{
|
||||
public:
|
||||
InputAllocatorPool(HDC hdc, HGLRC hglrc);
|
||||
|
||||
// IUnknown interface
|
||||
ULONG STDMETHODCALLTYPE AddRef() override;
|
||||
ULONG STDMETHODCALLTYPE Release() override;
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppv) override;
|
||||
|
||||
// IDeckLinkVideoBufferAllocatorProvider interface
|
||||
HRESULT STDMETHODCALLTYPE GetVideoBufferAllocator(
|
||||
/* [in] */ unsigned int bufferSize,
|
||||
/* [in] */ unsigned int width,
|
||||
/* [in] */ unsigned int height,
|
||||
/* [in] */ unsigned int rowBytes,
|
||||
/* [in] */ BMDPixelFormat pixelFormat,
|
||||
/* [out] */ IDeckLinkVideoBufferAllocator** allocator) override;
|
||||
|
||||
private:
|
||||
std::atomic<ULONG> mRefCount;
|
||||
std::map<unsigned int, CComPtr<PinnedMemoryAllocator> > mAllocatorBySize;
|
||||
HDC mHDC;
|
||||
HGLRC mHGLRC;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// DeckLinkVideoBuffer
|
||||
////////////////////////////////////////////
|
||||
class DeckLinkVideoBuffer : public IDeckLinkVideoBuffer
|
||||
{
|
||||
public:
|
||||
explicit DeckLinkVideoBuffer(std::shared_ptr<void>& buffer, PinnedMemoryAllocator* parent);
|
||||
virtual ~DeckLinkVideoBuffer() = default;
|
||||
|
||||
// IUnknown interface
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override;
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
|
||||
virtual ULONG STDMETHODCALLTYPE Release(void) override;
|
||||
|
||||
// IDeckLinkVideoBuffer interface
|
||||
virtual HRESULT STDMETHODCALLTYPE GetBytes(void** buffer) override;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetSize(uint64_t* size) override;
|
||||
virtual HRESULT STDMETHODCALLTYPE StartAccess(BMDBufferAccessFlags flags) override;
|
||||
virtual HRESULT STDMETHODCALLTYPE EndAccess(BMDBufferAccessFlags flags) override;
|
||||
|
||||
private:
|
||||
CComPtr<PinnedMemoryAllocator> mParentAllocator;
|
||||
std::atomic<ULONG> mRefCount;
|
||||
std::shared_ptr<void> mBuffer;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Capture Delegate Class
|
||||
////////////////////////////////////////////
|
||||
class CaptureDelegate : public IDeckLinkInputCallback
|
||||
{
|
||||
OpenGLComposite* m_pOwner;
|
||||
LONG mRefCount;
|
||||
|
||||
public:
|
||||
CaptureDelegate(OpenGLComposite* pOwner);
|
||||
|
||||
// IUnknown needs only a dummy implementation
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID* ppv);
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||
virtual ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioPacket);
|
||||
virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode* newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Render Delegate Class
|
||||
////////////////////////////////////////////
|
||||
class PlayoutDelegate : public IDeckLinkVideoOutputCallback
|
||||
{
|
||||
OpenGLComposite* m_pOwner;
|
||||
LONG mRefCount;
|
||||
|
||||
public:
|
||||
PlayoutDelegate(OpenGLComposite* pOwner);
|
||||
|
||||
// IUnknown needs only a dummy implementation
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID* ppv);
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||
virtual ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result);
|
||||
virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped();
|
||||
};
|
||||
Reference in New Issue
Block a user