[Bf-blender-cvs] [94e1a67] decklink: BGE VideoTexture: 3D support+performance boost on DeckLink.

Benoit Bolsee noreply at git.blender.org
Fri Apr 10 21:20:22 CEST 2015


Commit: 94e1a67383e1a576e50758f26b6e8d2c4f29ad61
Author: Benoit Bolsee
Date:   Fri Apr 10 21:07:51 2015 +0200
Branches: decklink
https://developer.blender.org/rB94e1a67383e1a576e50758f26b6e8d2c4f29ad61

BGE VideoTexture: 3D support+performance boost on DeckLink.

ImageViewport will now skip the unnecessary RGBA32 filtering if the capture
is already in the RGBA format. This will be the case if alpha=True and no
filter is set. This saves a great deal of CPU.
Add swap attribute to DeckLink to skip pixel format conversion between
VideoTexture internal (RGBA) and DeckLink (BGRA). This is to test the
benefit of passing the image directly to the board without intermediate
copy => great boost of performance.
However, it will be necessary to change the VideoTexture internal pixel
format from RGBA to BGRA.

3D stream is now fully supported on DeckLink, the right eye image is
passed via a new 'right' attribute (name not definitive). To generate this
image one can simply put a second camera to figure the right eye and
capture its view with ImageRende.

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

M	source/gameengine/VideoTexture/CMakeLists.txt
M	source/gameengine/VideoTexture/DeckLink.cpp
M	source/gameengine/VideoTexture/DeckLink.h
M	source/gameengine/VideoTexture/ImageViewport.cpp
M	source/gameengine/VideoTexture/VideoDeckLink.cpp
M	source/gameengine/VideoTexture/VideoDeckLink.h

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

diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt
index e8eb005..aa7267a 100644
--- a/source/gameengine/VideoTexture/CMakeLists.txt
+++ b/source/gameengine/VideoTexture/CMakeLists.txt
@@ -47,6 +47,7 @@ set(INC
 	../../../intern/string
 	../../../intern/decklink
 	../../../intern/gpudirect
+	../../../intern/atomic
 )
 
 set(INC_SYS
diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp
index da4d7da..8cc8614 100644
--- a/source/gameengine/VideoTexture/DeckLink.cpp
+++ b/source/gameengine/VideoTexture/DeckLink.cpp
@@ -33,23 +33,10 @@
 // implementation
 
 #include "PyObjectPlus.h"
-#include <structmember.h>
-
-#include "KX_GameObject.h"
-#include "KX_Light.h"
-#include "RAS_MeshObject.h"
-#include "RAS_ILightObject.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_image_types.h"
-#include "IMB_imbuf_types.h"
-#include "BKE_image.h"
-
-#include "MEM_guardedalloc.h"
-
 #include "KX_KetsjiEngine.h"
 #include "KX_PythonInit.h"
 #include "DeckLink.h"
+#include "atomic_ops.h"
 
 #include <memory.h>
 
@@ -179,6 +166,90 @@ HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat
 	return S_OK;
 }
 
+class DeckLinkFrameWrapper : public IDeckLinkVideoFrame
+{
+public:
+	// From IUknown
+	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv)	{ return E_NOTIMPL;	}
+	virtual ULONG STDMETHODCALLTYPE AddRef(void)	{ return 1U; }
+	virtual ULONG STDMETHODCALLTYPE Release(void)	{ return 1U; }
+	// From IDeckLinkVideoFrame
+	virtual long STDMETHODCALLTYPE GetWidth(void) { return mpFrame->GetWidth(); }
+	virtual long STDMETHODCALLTYPE GetHeight(void) { return mpFrame->GetHeight(); }
+	virtual long STDMETHODCALLTYPE GetRowBytes(void) { return mpFrame->GetRowBytes(); }
+	virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return mpFrame->GetPixelFormat(); }
+	virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags(void) { return mpFrame->GetFlags(); }
+	// this is the only function that is modified: return our buffer instead
+	virtual HRESULT STDMETHODCALLTYPE GetBytes(void **buffer) { *buffer = mpBuffer; return S_OK; }
+	virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode **timecode) 
+		{ return mpFrame->GetTimecode(format, timecode); }
+	virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary)
+		{ return mpFrame->GetAncillaryData(ancillary); }
+	// constructor
+	DeckLinkFrameWrapper(IDeckLinkVideoFrame *theFrame, void *theBuffer)
+	{
+		mpBuffer = theBuffer;
+		mpFrame = theFrame;
+	}
+	// no destructor, it's just a wrapper
+private:
+	IDeckLinkVideoFrame *mpFrame;
+	void *mpBuffer;
+};
+
+class DeckLink3DFrameWrapper : public IDeckLinkVideoFrame, IDeckLinkVideoFrame3DExtensions
+{
+public:
+	// IUnknown
+	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv)
+	{
+		if (iid == IID_IDeckLinkVideoFrame3DExtensions)
+		{
+			if (mpRightEye)
+			{
+				*ppv = (IDeckLinkVideoFrame3DExtensions*)this;
+				return S_OK;
+			}
+		}
+		return E_NOTIMPL;
+	}
+	virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1U;  }
+	virtual ULONG STDMETHODCALLTYPE Release(void) { return 1U; }
+	// IDeckLinkVideoFrame
+	virtual long STDMETHODCALLTYPE GetWidth(void) {	return mpLeftEye->GetWidth(); }
+	virtual long STDMETHODCALLTYPE GetHeight(void) { return mpLeftEye->GetHeight(); }
+	virtual long STDMETHODCALLTYPE GetRowBytes(void) { return mpLeftEye->GetRowBytes(); }
+	virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return mpLeftEye->GetPixelFormat(); }
+	virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags(void) { return mpLeftEye->GetFlags(); }
+	virtual HRESULT STDMETHODCALLTYPE GetBytes(void **buffer) { return mpLeftEye->GetBytes(buffer); }
+	virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format,IDeckLinkTimecode **timecode)
+		{ return mpLeftEye->GetTimecode(format, timecode); }
+	virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) 
+		{ return mpLeftEye->GetAncillaryData(ancillary); }
+	// IDeckLinkVideoFrame3DExtensions
+	virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat(void)
+	{
+		return bmdVideo3DPackingLeftOnly;
+	}
+	virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye(
+		/* [out] */ IDeckLinkVideoFrame **rightEyeFrame)
+	{
+		mpRightEye->AddRef();
+		*rightEyeFrame = mpRightEye;
+		return S_OK;
+	}
+	// Constructor
+	DeckLink3DFrameWrapper(IDeckLinkVideoFrame *leftEye, IDeckLinkVideoFrame *rightEye)
+	{
+		mpLeftEye = leftEye;
+		mpRightEye = rightEye;
+	}
+	// no need for a destructor, it's just a wrapper
+private:
+	IDeckLinkVideoFrame *mpLeftEye;
+	IDeckLinkVideoFrame *mpRightEye;
+};
+
 static void decklink_Reset(DeckLink *self)
 {
 	self->m_lastClock = 0.0;
@@ -189,35 +260,57 @@ static void decklink_Reset(DeckLink *self)
 	self->mHDKeyingSupported = false;
 	self->mSize[0] = 0;
 	self->mSize[1] = 0;
-	self->mFrame = NULL;
+	self->mLeftFrame = NULL;
+	self->mRightFrame = NULL;
 	self->mKeyer = NULL;
 	self->mUseKeying = false;
 	self->mKeyingLevel = 255;
+	self->mUseExtend = false;
+	self->mUseSwap = false;
 }
 
 #ifdef __BIG_ENDIAN__
-#define CONV_PIXEL(o,i)	(o=((i)>>8)+(((i)&0xFF)<<24))
+#define CONV_PIXEL(i)	((((i)>>16)&0xFF00)+(((i)&0xFF00)<<16)+((i)&0xFF00FF))
 #else
-#define CONV_PIXEL(o,i)	(o=((i)<<8)+(((i)&0xFF000000)>>24))
+#define CONV_PIXEL(i)	((((i)&0xFF)<<16)+(((i)>>16)&0xFF)+((i)&0xFF00FF00))
 #endif
 
-// adapt the pixel format from VideoTexture (RGBA) to DeckLink (ARGB)
-static void decklink_ConvImage(u_int *dest, const short *destSize, u_int *source, const short *srcSize, bool extend)
+// adapt the pixel format from VideoTexture (RGBA) to DeckLink (BGRA)
+// return false if no conversion at all is necessary
+static bool decklink_ConvImage(u_int *dest, const short *destSize, const u_int *source, const short *srcSize, bool extend, bool swap)
 {
 	short w, h, x, y;
-	u_int *s, *d;
+	const u_int *s;
+	u_int *d;
+	bool sameSize = (destSize[0] == srcSize[0] && destSize[1] == srcSize[1]);
 
-	if ((destSize[0] == srcSize[0] && destSize[1] == srcSize[1]) || !extend)
+	if (sameSize || !extend)
 	{
-		// here we convert pixel by pixel
-		w = (destSize[0] < srcSize[0]) ? destSize[0] : srcSize[0];
-		h = (destSize[1] < srcSize[1]) ? destSize[1] : srcSize[1];
-		for (y = 0; y < h; ++y)
+		if (sameSize && !swap)
+		{
+			//memcpy(dest, source, 4 * srcSize[0] * srcSize[1]);
+			//return true;
+			return false;
+		}
+		else
 		{
-			s = source + y*srcSize[0];
-			d = dest + y*destSize[0];
-			for (x = 0; x < w; ++x, ++s, ++d)
-				CONV_PIXEL(*d, *s);
+			// here we convert pixel by pixel
+			w = (destSize[0] < srcSize[0]) ? destSize[0] : srcSize[0];
+			h = (destSize[1] < srcSize[1]) ? destSize[1] : srcSize[1];
+			for (y = 0; y < h; ++y)
+			{
+				s = source + y*srcSize[0];
+				d = dest + y*destSize[0];
+				if (swap)
+				{
+					for (x = 0; x < w; ++x, ++s, ++d)
+						*d = CONV_PIXEL(*s);
+				}
+				else
+				{
+					memcpy(d, s, 4 * w);
+				}
+			}
 		}
 	}
 	else
@@ -250,7 +343,7 @@ static void decklink_ConvImage(u_int *dest, const short *destSize, u_int *source
 						// decrease accum
 						accWidth -= srcSize[0];
 						// convert pixel
-						CONV_PIXEL(*d, *s);
+						*d = (swap) ? CONV_PIXEL(*s) : *s;
 						// next pixel
 						++d;
 					}
@@ -262,6 +355,7 @@ static void decklink_ConvImage(u_int *dest, const short *destSize, u_int *source
 				s += srcSize[0];
 		}
 	}
+	return true;
 }
 
 // DeckLink object allocation
@@ -271,8 +365,8 @@ static PyObject *DeckLink_new(PyTypeObject *type, PyObject *args, PyObject *kwds
 	DeckLink * self = reinterpret_cast<DeckLink*>(type->tp_alloc(type, 0));
 	// initialize object structure
 	decklink_Reset(self);
-	// m_source is a python object, it's handled by python
-	self->m_source = NULL;
+	// m_leftEye is a python object, it's handled by python
+	self->m_leftEye = NULL;
 	// return allocated object
 	return reinterpret_cast<PyObject*>(self);
 }
@@ -287,7 +381,7 @@ int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure);
 static void DeckLink_dealloc(DeckLink *self)
 {
 	// release renderer
-	Py_XDECREF(self->m_source);
+	Py_XDECREF(self->m_leftEye);
 	// close decklink
 	PyObject *ret = DeckLink_close(self);
 	Py_DECREF(ret);
@@ -400,7 +494,7 @@ static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds)
 		{
 			if (pDisplayMode->GetDisplayMode() == self->mDisplayMode
 				&& (pDisplayMode->GetFlags() & displayFlags) == displayFlags
-				&& self->mDLOutput->DoesSupportVideoMode(self->mDisplayMode, bmdFormat8BitARGB, outputFlags, &support, NULL) == S_OK
+				&& self->mDLOutput->DoesSupportVideoMode(self->mDisplayMode, bmdFormat8BitBGRA, outputFlags, &support, NULL) == S_OK
 				&& (support == bmdDisplayModeSupported || support == bmdDisplayModeSupportedWithConversion))
 			{
 				break;
@@ -419,12 +513,19 @@ static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds)
 			// this shouldn't fail
 			THRWEXCP(DeckLinkOpenCard, S_OK);
 
-		if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitARGB, bmdFrameFlagFlipVertical, &self->mFrame) != S_OK)
+		if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mLeftFrame) != S_OK)
 			THRWEXCP(DeckLinkInternalError, S_OK);
-
 		// clear alpha channel in the frame buffer
-		self->mFrame->GetBytes((void **)&bytes);
+		self->mLeftFrame->GetBytes((void **)&bytes);
 		memset(bytes, 0, 4 * self->mSize[0] * self->mSize[1]);
+		if (self->mUse3D)
+		{
+			if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mRightFrame) != S_OK)
+				THRWEXCP(DeckLinkInternalError, S_OK);
+			// clear alpha channel in the frame buffer
+			self->mRightFrame->GetBytes((void **)&bytes);
+			memset(bytes, 0, 4 * self->mSize[0] * self->mSize[1]);
+		}
 	}
 	catch (Exception & exp)
 	{ 
@@ -440,8 +541,10 @@ static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds)
 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list