16bit processing
This commit is contained in:
@@ -2,311 +2,6 @@
|
||||
|
||||
#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
|
||||
////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user