280 lines
9.4 KiB
C++
280 lines
9.4 KiB
C++
/* -LICENSE-START-
|
|
** Copyright (c) 2012 Blackmagic Design
|
|
**
|
|
** Permission is hereby granted, free of charge, to any person or organization
|
|
** obtaining a copy of the software and accompanying documentation (the
|
|
** "Software") to use, reproduce, display, distribute, sub-license, execute,
|
|
** and transmit the Software, and to prepare derivative works of the Software,
|
|
** and to permit third-parties to whom the Software is furnished to do so, in
|
|
** accordance with:
|
|
**
|
|
** (1) if the Software is obtained from Blackmagic Design, the End User License
|
|
** Agreement for the Software Development Kit ("EULA") available at
|
|
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
|
|
**
|
|
** (2) if the Software is obtained from any third party, such licensing terms
|
|
** as notified by that third party,
|
|
**
|
|
** and all subject to the following:
|
|
**
|
|
** (3) the copyright notices in the Software and this entire statement,
|
|
** including the above license grant, this restriction and the following
|
|
** disclaimer, must be included in all copies of the Software, in whole or in
|
|
** part, and all derivative works of the Software, unless such copies or
|
|
** derivative works are solely in the form of machine-executable object code
|
|
** generated by a source language processor.
|
|
**
|
|
** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
** DEALINGS IN THE SOFTWARE.
|
|
**
|
|
** A copy of the Software is available free of charge at
|
|
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
|
|
**
|
|
** -LICENSE-END-
|
|
*/
|
|
|
|
#ifndef __OPENGL_COMPOSITE_H__
|
|
#define __OPENGL_COMPOSITE_H__
|
|
|
|
#include <windows.h>
|
|
#include <process.h>
|
|
#include <tchar.h>
|
|
#include <gl/gl.h>
|
|
#include <gl/glu.h>
|
|
|
|
#include <objbase.h>
|
|
#include <atlbase.h>
|
|
#include <comutil.h>
|
|
#include "DeckLinkAPI_h.h"
|
|
|
|
#include "VideoFrameTransfer.h"
|
|
#include "RuntimeHost.h"
|
|
|
|
#include <atomic>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <deque>
|
|
|
|
class PlayoutDelegate;
|
|
class CaptureDelegate;
|
|
class PinnedMemoryAllocator;
|
|
class ControlServer;
|
|
|
|
|
|
class OpenGLComposite
|
|
{
|
|
public:
|
|
OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC);
|
|
~OpenGLComposite();
|
|
|
|
bool InitDeckLink();
|
|
bool Start();
|
|
bool Stop();
|
|
bool ReloadShader();
|
|
std::string GetRuntimeStateJson() const;
|
|
bool SelectShader(const std::string& shaderId, std::string& error);
|
|
bool UpdateParameterJson(const std::string& shaderId, const std::string& parameterId, const std::string& valueJson, std::string& error);
|
|
bool SetBypassEnabled(bool bypassEnabled, std::string& error);
|
|
bool SetMixAmount(double mixAmount, std::string& error);
|
|
|
|
void resizeGL(WORD width, WORD height);
|
|
void paintGL();
|
|
|
|
void VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame, bool hasNoInputSource);
|
|
void PlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result);
|
|
|
|
private:
|
|
void resizeWindow(int width, int height);
|
|
bool CheckOpenGLExtensions();
|
|
|
|
CaptureDelegate* mCaptureDelegate;
|
|
PlayoutDelegate* mPlayoutDelegate;
|
|
HWND hGLWnd;
|
|
HDC hGLDC;
|
|
HGLRC hGLRC;
|
|
CRITICAL_SECTION pMutex;
|
|
|
|
// DeckLink
|
|
IDeckLinkInput* mDLInput;
|
|
IDeckLinkOutput* mDLOutput;
|
|
std::deque<IDeckLinkMutableVideoFrame*> mDLOutputVideoFrameQueue;
|
|
PinnedMemoryAllocator* mPlayoutAllocator;
|
|
BMDTimeValue mFrameDuration;
|
|
BMDTimeScale mFrameTimescale;
|
|
unsigned mTotalPlayoutFrames;
|
|
unsigned mFrameWidth;
|
|
unsigned mFrameHeight;
|
|
bool mHasNoInputSource;
|
|
|
|
// OpenGL data
|
|
bool mFastTransferExtensionAvailable;
|
|
GLuint mCaptureTexture;
|
|
GLuint mFBOTexture;
|
|
GLuint mUnpinnedTextureBuffer;
|
|
GLuint mIdFrameBuf;
|
|
GLuint mIdColorBuf;
|
|
GLuint mIdDepthBuf;
|
|
GLuint mFullscreenVAO;
|
|
GLuint mGlobalParamsUBO;
|
|
GLuint mProgram;
|
|
GLuint mVertexShader;
|
|
GLuint mFragmentShader;
|
|
GLsizeiptr mGlobalParamsUBOSize;
|
|
int mViewWidth;
|
|
int mViewHeight;
|
|
std::unique_ptr<RuntimeHost> mRuntimeHost;
|
|
std::unique_ptr<ControlServer> mControlServer;
|
|
|
|
bool InitOpenGLState();
|
|
bool compileFragmentShader(int errorMessageSize, char* errorMessage);
|
|
void destroyShaderProgram();
|
|
void renderEffect();
|
|
bool PollRuntimeChanges();
|
|
void broadcastRuntimeState();
|
|
bool updateGlobalParamsBuffer(const RuntimeRenderState& state);
|
|
};
|
|
|
|
////////////////////////////////////////////
|
|
// 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; // Dual-purpose: allocator owns mem this points to, and to access transferFrame() via a QueryInterface
|
|
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 ();
|
|
};
|
|
|
|
#endif // __OPENGL_COMPOSITE_H__
|