[Bf-blender-cvs] [0b7337e] decklink: BGE DeckLink: support capture in Linux - part I.

Benoit Bolsee noreply at git.blender.org
Fri Apr 17 00:00:08 CEST 2015


Commit: 0b7337ed1902877a15c16ad85bd29e0d84270398
Author: Benoit Bolsee
Date:   Thu Apr 16 23:53:04 2015 +0200
Branches: decklink
https://developer.blender.org/rB0b7337ed1902877a15c16ad85bd29e0d84270398

BGE DeckLink: support capture in Linux - part I.

Capture works: I can see the frame coming in but passing them to the GPU
doesn't work yet. I'm using standard OGL function though.. TBC.
them to the GPU.

===================================================================

M	source/gameengine/VideoTexture/VideoDeckLink.cpp
M	source/gameengine/VideoTexture/VideoDeckLink.h

===================================================================

diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp
index 386d470..a8cd69a 100644
--- a/source/gameengine/VideoTexture/VideoDeckLink.cpp
+++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp
@@ -47,11 +47,12 @@
 #include "atomic_ops.h"
 
 extern ExceptionID DeckLinkInternalError;
-ExceptionID SourceVideoOnlyCapture, VideoDeckLinkBadFormat, VideoDeckLinkOpenCard, VideoDeckLinkDvpInternalError;
+ExceptionID SourceVideoOnlyCapture, VideoDeckLinkBadFormat, VideoDeckLinkOpenCard, VideoDeckLinkDvpInternalError, VideoDeckLinkPinMemoryError;
 ExpDesc SourceVideoOnlyCaptureDesc(SourceVideoOnlyCapture, "This video source only allows live capture");
 ExpDesc VideoDeckLinkBadFormatDesc(VideoDeckLinkBadFormat, "Invalid or unsupported capture format, should be <mode>/<pixel>[/3D]");
 ExpDesc VideoDeckLinkOpenCardDesc(VideoDeckLinkOpenCard, "Cannot open capture card, check if driver installed");
 ExpDesc VideoDeckLinkDvpInternalErrorDesc(VideoDeckLinkDvpInternalError, "DVP API internal error, please report");
+ExpDesc VideoDeckLinkPinMemoryErrorDesc(VideoDeckLinkPinMemoryError, "Error pinning memory");
 
 
 #ifdef WIN32
@@ -107,7 +108,7 @@ struct SyncInfo
 class TextureTransferDvp : public TextureTransfer
 {
 public:
-	TextureTransferDvp(DVPBufferHandle dvpTextureHandle, TextureDesc *pDesc, void *address)
+	TextureTransferDvp(DVPBufferHandle dvpTextureHandle, TextureDesc *pDesc, void *address, u_int allocatedSize)
 	{
 		DVPSysmemBufferDesc sysMemBuffersDesc;
 		DVPStatus status;
@@ -117,6 +118,13 @@ public:
 		mDvpSysMemHandle = 0;
 		mDvpTextureHandle = 0;
 		mTextureHeight = 0;
+		mAllocatedSize = 0;
+		mBuffer = NULL;
+
+		if (!_PinBuffer(address, allocatedSize))
+			THRWEXCP(VideoDeckLinkPinMemoryError, S_OK);
+		mAllocatedSize = allocatedSize;
+		mBuffer = address;
 
 		try
 		{
@@ -142,12 +150,12 @@ public:
 				sysMemBuffersDesc.type = (pDesc->type == GL_UNSIGNED_INT_8_8_8_8) ? DVP_UNSIGNED_INT_8_8_8_8 : DVP_UNSIGNED_INT_8_8_8_8_REV;
 			}
 			sysMemBuffersDesc.size = pDesc->width * pDesc->height * 4;
-			sysMemBuffersDesc.bufAddr = address;
+			sysMemBuffersDesc.bufAddr = mBuffer;
 			DVP_CHECK(dvpCreateBuffer(&sysMemBuffersDesc, &mDvpSysMemHandle));
 			status = dvpBindToGLCtx(mDvpSysMemHandle);
 			DVP_CHECK(status);
 			mDvpTextureHandle = dvpTextureHandle;
-			mTextureHeight = pDesc->height; 7680 / 1920;
+			mTextureHeight = pDesc->height;
 		}
 		catch (Exception &)
 		{
@@ -197,12 +205,16 @@ private:
 			delete mExtSync;
 		if (mGpuSync)
 			delete mGpuSync;
+		if (mBuffer)
+			_UnpinBuffer(mBuffer, mAllocatedSize);
 	}
 	SyncInfo*				mExtSync;
 	SyncInfo*				mGpuSync;
 	DVPBufferHandle			mDvpSysMemHandle;
 	DVPBufferHandle			mDvpTextureHandle;
 	u_int					mTextureHeight;
+	u_int					mAllocatedSize;
+	void*					mBuffer;
 };
 
 uint32_t	TextureTransferDvp::mBufferAddrAlignment;
@@ -214,6 +226,64 @@ uint32_t	TextureTransferDvp::mSemaphorePayloadSize;
 
 #endif
 
+class TextureTransferOGL : public TextureTransfer
+{
+public:
+	TextureTransferOGL(GLuint texId, TextureDesc *pDesc, void *address)
+	{
+		memcpy(&mDesc, pDesc, sizeof(mDesc));
+		mTexId = texId;
+		mBuffer = address;
+
+		// as we cache transfer object, we will create one texture to hold the buffer
+		glGenBuffers(1, &mUnpinnedTextureBuffer);
+		// create a storage for it
+		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
+		glBufferData(GL_PIXEL_UNPACK_BUFFER, pDesc->size, NULL, GL_DYNAMIC_DRAW);
+		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+	}
+	~TextureTransferOGL()
+	{
+		glDeleteBuffers(1, &mUnpinnedTextureBuffer);
+	}
+
+	virtual void PerformTransfer()
+	{
+		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
+		glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, mDesc.size, mBuffer);
+		glBindTexture(GL_TEXTURE_2D, mTexId);
+		// NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data
+		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL);
+		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+	}
+private:
+	// intermediate texture to receive the buffer
+	GLuint mUnpinnedTextureBuffer;
+	// target texture to receive the image
+	GLuint mTexId;
+	// buffer
+	void *mBuffer;
+	// characteristic of the image
+	TextureDesc mDesc;
+};
+
+bool TextureTransfer::_PinBuffer(void *address, u_int size)
+{
+#ifdef WIN32
+	return VirtualLock(address, size);
+#else
+	// Linux doesn't have the equivalent?
+	return true;
+#endif
+}
+
+void TextureTransfer::_UnpinBuffer(void* address, u_int size)
+{
+#ifdef WIN32
+	VirtualUnlock(address, size);
+#endif
+}
+
 
 
 ////////////////////////////////////////////
@@ -253,11 +323,10 @@ bool PinnedMemoryAllocator::ReserveMemory(size_t size)
 
 PinnedMemoryAllocator::PinnedMemoryAllocator(unsigned cacheSize, size_t memSize) :
 mRefCount(1U),
-mBufferCacheSize(cacheSize),
-mUnpinnedTextureBuffer(0)
 #ifdef WIN32
-, mDvpCaptureTextureHandle(0)
+mDvpCaptureTextureHandle(0),
 #endif
+mBufferCacheSize(cacheSize)
 {
 	pthread_mutex_init(&mMutex, NULL);
 	// do it once
@@ -279,12 +348,7 @@ mUnpinnedTextureBuffer(0)
 
 		mGPUDirectInitialized = true;
 	}
-	if (!mHasDvp && !mHasAMDPinnedMemory)
-	{
-		// if we cannot use GPUDirect, we will send the video to the GPU using OGL buffer
-		glGenBuffers(1, &mUnpinnedTextureBuffer);
-	}
-	else
+	if (mHasDvp || mHasAMDPinnedMemory)
 	{
 		ReserveMemory(memSize);
 	}
@@ -307,31 +371,12 @@ PinnedMemoryAllocator::~PinnedMemoryAllocator()
 		_ReleaseBuffer(address);
 	}
 
-	if (mUnpinnedTextureBuffer)
-		glDeleteBuffers(1, &mUnpinnedTextureBuffer);
 #ifdef WIN32
 	if (mDvpCaptureTextureHandle)
 		dvpDestroyBuffer(mDvpCaptureTextureHandle);
 #endif
 }
 
-bool PinnedMemoryAllocator::_PinBuffer(void *address, u_int size)
-{
-#ifdef WIN32
-	return VirtualLock(address, size);
-#else
-	// Linux doesn't have the equivalent?
-	return true;
-#endif
-}
-
-void PinnedMemoryAllocator::_UnpinBuffer(void* address, u_int size)
-{
-#ifdef WIN32
-	VirtualUnlock(address, size);
-#endif
-}
-
 void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId)
 {
 	u_int allocatedSize = 0;
@@ -367,9 +412,7 @@ void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc,
 		Unlock();
 		if (!pTransfer)
 		{
-			if (!_PinBuffer(address, allocatedSize))
-				return;
-			pTransfer = new TextureTransferDvp(mDvpCaptureTextureHandle, texDesc, address);
+			pTransfer = new TextureTransferDvp(mDvpCaptureTextureHandle, texDesc, address, allocatedSize);
 			if (pTransfer)
 			{
 				Lock();
@@ -386,7 +429,22 @@ void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc,
 	}
 	else
 	{
-		pTransfer = NULL;
+		Lock();
+		if (mPinnedBuffer.count(address) > 0)
+		{
+			pTransfer = mPinnedBuffer[address];
+		}
+		Unlock();
+		if (!pTransfer)
+		{
+			pTransfer = new TextureTransferOGL(texId, texDesc, address);
+			if (pTransfer)
+			{
+				Lock();
+				mPinnedBuffer[address] = pTransfer;
+				Unlock();
+			}
+		}
 	}
 	if (pTransfer)
 		pTransfer->PerformTransfer();
@@ -400,13 +458,13 @@ HRESULT STDMETHODCALLTYPE	PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/,
 
 ULONG STDMETHODCALLTYPE		PinnedMemoryAllocator::AddRef(void)
 {
-	return atomic_add_uint32(&mRefCount, 1U)+1U;
+    return atomic_add_uint32(&mRefCount, 1U);
 }
 
 ULONG STDMETHODCALLTYPE		PinnedMemoryAllocator::Release(void)
 {
 	uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U);
-	if (--newCount == 0)
+    if (newCount == 0)
 		delete this;
 	return (ULONG)newCount;
 }
@@ -419,7 +477,7 @@ HRESULT STDMETHODCALLTYPE	PinnedMemoryAllocator::AllocateBuffer(dl_size_t buffer
 	{
 		// Allocate memory on a page boundary
 		// Note: aligned alloc exist in Blender but only for small alignment, use direct allocation then.
-		// Note: the DeckLink API tries to allocate up to 65 buffer in advance, we will limit this to 3
+		// Note: the DeckLink API tries to allocate up to 65 buffer in advance, we will limit this to 5
 		//       because we don't need any caching
 		if (mAllocatedSize.size() >= 5)
 			*allocatedBuffer = NULL;
@@ -463,7 +521,6 @@ HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::ReleaseBuffer(void* buffer)
 
 HRESULT PinnedMemoryAllocator::_ReleaseBuffer(void* buffer)
 {
-	u_int allocatedSize = 0;
 	TextureTransfer *pTransfer;
 	if (mAllocatedSize.count(buffer) == 0)
 	{
@@ -473,10 +530,8 @@ HRESULT PinnedMemoryAllocator::_ReleaseBuffer(void* buffer)
 	else
 	{
 		// No room left in cache, so un-pin (if it was pinned) and free this buffer
-		allocatedSize = mAllocatedSize[buffer];
 		if (mPinnedBuffer.count(buffer) > 0)
 		{
-			_UnpinBuffer(buffer, allocatedSize);
 			pTransfer = mPinnedBuffer[buffer];
 			mPinnedBuffer.erase(buffer);
 			delete pTransfer;
@@ -780,11 +835,10 @@ void VideoDeckLink::openCam (char *format, short camIdx)
 		if (mTextureDesc.stride != mTextureDesc.width * 4)
 			THRWEXCP(VideoDeckLinkBadFormat, S_OK);
 	}
-
 	// custom allocator, 3 frame in cache should be enough
 	// make sure we allow up to 10 frame in memory for pinning
 	// note: some pixel format take more than 4 bytes but the difference is small (9/8 versus 1)
-	mpAllocator = new PinnedMemoryAllocator(3, mFrameWidth*mTextureDesc.height * 4 * 10);
+    mpAllocator = new PinnedMemoryAllocator(3, mFrameWidth*mTextureDesc.height * 4 * 10);
 
 	if (mDLInput->SetVideoInputFrameMemoryAllocator(mpAllocator) != S_OK)
 		THRWEXCP(DeckLinkInternalError, S_OK);
@@ -879,7 +933,6 @@ void VideoDeckLink::calcImage (unsigned int texId, double ts)
 		{
 			u_int rowSize = pFrame->GetRowBytes();
 			u_int textureSize = rowSize * pFrame->GetHeight();
-			u_int expectedSize;
 			void* videoPixels = NULL;
 			void* rightEyePixels = NULL;
 			if (!mTextureDesc.stride)
@@ -910,8 +963,8 @@ void VideoDeckLink::calcImage (unsigned int texId, double ts)
 					if (if3DExtensions)
 						if3DExtensions->Release();
 				}
-				expectedSize = mTextureDesc.width * mTextureDesc.height * 4;
-				if (expectedSize == textureSize)
+                mTextureDesc.size = mTextureDesc.width * mTextureDesc.height * 4;
+				if (mTextureDesc.size == textureSize)
 				{
 					// this means that both left and right frame are contiguous and that ther

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list