[Bf-blender-cvs] [3f02a17] decklink: BGE: Fill-in DeckLink object.

Benoit Bolsee noreply at git.blender.org
Mon Apr 6 16:51:05 CEST 2015


Commit: 3f02a17bba87c340dda3e6e94f9fdb48778ca556
Author: Benoit Bolsee
Date:   Mon Apr 6 16:18:06 2015 +0200
Branches: decklink
https://developer.blender.org/rB3f02a17bba87c340dda3e6e94f9fdb48778ca556

BGE: Fill-in DeckLink object.

Implement the DeckLink object to output on DeckLink card. It takes a
source like the Texture object and gets the image the same way.

API:
dl = bge.texture.DeckLink(0, "HD1080p24")  # card nb, mode
dl.source = bge.texture.ImageViewport()
dl.source.whole = True
dl.refresh(True)

Known issue: using ImageViewport as source will not set the alpha channel
right. This is because the framebuffer by default will not have an alpha
channel. This can be solved either by inserting a 'green' filter that will
convert the background color to alpha, or enable the alpha channel on the
framebuffer (require change in Ghost).

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

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

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

diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp
index bb78992..9bfb041 100644
--- a/source/gameengine/VideoTexture/DeckLink.cpp
+++ b/source/gameengine/VideoTexture/DeckLink.cpp
@@ -57,6 +57,211 @@
 #define CATCH_EXCP catch (Exception & exp) \
 { exp.report(); return NULL; }
 
+static struct
+{
+	const char *name;
+	BMDDisplayMode mode;
+} sModeStringTab[] = {
+	{ "NTSC", bmdModeNTSC },
+	{ "NTSC2398", bmdModeNTSC2398 },
+	{ "PAL", bmdModePAL },
+	{ "NTSCp", bmdModeNTSCp },
+	{ "PALp", bmdModePALp },
+
+	/* HD 1080 Modes */
+
+	{ "HD1080p2398", bmdModeHD1080p2398 },
+	{ "HD1080p24", bmdModeHD1080p24 },
+	{ "HD1080p25", bmdModeHD1080p25 },
+	{ "HD1080p2997", bmdModeHD1080p2997 },
+	{ "HD1080p30", bmdModeHD1080p30 },
+	{ "HD1080i50", bmdModeHD1080i50 },
+	{ "HD1080i5994", bmdModeHD1080i5994 },
+	{ "HD1080i6000", bmdModeHD1080i6000 },
+	{ "HD1080p50", bmdModeHD1080p50 },
+	{ "HD1080p5994", bmdModeHD1080p5994 },
+	{ "HD1080p6000", bmdModeHD1080p6000 },
+
+	/* HD 720 Modes */
+
+	{ "HD720p50", bmdModeHD720p50 },
+	{ "HD720p5994", bmdModeHD720p5994 },
+	{ "HD720p60", bmdModeHD720p60 },
+
+	/* 2k Modes */
+
+	{ "2k2398", bmdMode2k2398 },
+	{ "2k24", bmdMode2k24 },
+	{ "2k25", bmdMode2k25 },
+
+	/* DCI Modes (output only) */
+
+	{ "2kDCI2398", bmdMode2kDCI2398 },
+	{ "2kDCI24", bmdMode2kDCI24 },
+	{ "2kDCI25", bmdMode2kDCI25 },
+
+	/* 4k Modes */
+
+	{ "4K2160p2398", bmdMode4K2160p2398 },
+	{ "4K2160p24", bmdMode4K2160p24 },
+	{ "4K2160p25", bmdMode4K2160p25 },
+	{ "4K2160p2997", bmdMode4K2160p2997 },
+	{ "4K2160p30", bmdMode4K2160p30 },
+	{ "4K2160p50", bmdMode4K2160p50 },
+	{ "4K2160p5994", bmdMode4K2160p5994 },
+	{ "4K2160p60", bmdMode4K2160p60 },
+	// sentinel
+	{ NULL }
+};
+
+static struct
+{
+	const char *name;
+	BMDPixelFormat format;
+} sFormatStringTab[] = {
+	{ "8BitYUV", bmdFormat8BitYUV },
+	{ "10BitYUV", bmdFormat10BitYUV },
+	{ "8BitARGB", bmdFormat8BitARGB },
+	{ "8BitBGRA", bmdFormat8BitBGRA },
+	{ "10BitRGB", bmdFormat10BitRGB },
+	{ "12BitRGB", bmdFormat12BitRGB },
+	{ "12BitRGBLE", bmdFormat12BitRGBLE },
+	{ "10BitRGBXLE", bmdFormat10BitRGBXLE },
+	{ "10BitRGBX", bmdFormat10BitRGBX },
+	// sentinel
+	{ NULL }
+};
+
+ExceptionID DeckLinkBadDisplayMode, DeckLinkBadPixelFormat;
+ExpDesc DeckLinkBadDisplayModeDesc(DeckLinkBadDisplayMode, "Invalid or unsupported display mode");
+ExpDesc DeckLinkBadPixelFormatDesc(DeckLinkBadPixelFormat, "Invalid or unsupported pixel format");
+
+HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode)
+{
+	int i;
+
+	if (len == 0)
+		len = strlen(format);
+	for (i = 0; sModeStringTab[i].name != NULL; i++) {
+		if (strlen(sModeStringTab[i].name) == len &&
+			!strncmp(sModeStringTab[i].name, format, len))
+		{
+			*displayMode = sModeStringTab[i].mode;
+			return S_OK;
+		}
+	}
+	if (len != 4)
+		THRWEXCP(DeckLinkBadDisplayMode, S_OK);
+	// assume the user entered directly the mode value as a 4 char string
+	*displayMode = (BMDDisplayMode)((((u_int)format[0]) << 24) + (((u_int)format[1]) << 16) + (((u_int)format[2]) << 8) + ((u_int)format[3]));
+	return S_OK;
+}
+
+HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *pixelFormat)
+{
+	int i;
+
+	if (!len)
+		len = strlen(format);
+	for (i = 0; sFormatStringTab[i].name != NULL; i++)
+	{
+		if (strlen(sFormatStringTab[i].name) == len &&
+			!strncmp(sFormatStringTab[i].name, format, len))
+		{
+			*pixelFormat = sFormatStringTab[i].format;
+			return S_OK;
+		}
+	}
+	if (len != 4)
+		THRWEXCP(DeckLinkBadPixelFormat, S_OK);
+	// assume the user entered directly the mode value as a 4 char string
+	*pixelFormat = (BMDPixelFormat)((((u_int)format[0]) << 24) + (((u_int)format[1]) << 16) + (((u_int)format[2]) << 8) + ((u_int)format[3]));
+	return S_OK;
+}
+
+static void decklink_Reset(DeckLink *self)
+{
+	self->m_lastClock = 0.0;
+	self->mDLOutput = NULL;
+	self->mUse3D = false;
+	self->mDisplayMode = bmdModeUnknown;
+	self->mKeyingSupported = false;
+	self->mHDKeyingSupported = false;
+	self->mSize[0] = 0;
+	self->mSize[1] = 0;
+	self->mFrame = NULL;
+	self->mKeyer = NULL;
+	self->mUseKeying = false;
+}
+
+#ifdef __BIG_ENDIAN__
+#define CONV_PIXEL(o,i)	(o=((i)>>8)+(((i)&0xFF)<<24))
+#else
+#define CONV_PIXEL(o,i)	(o=((i)<<8)+(((i)&0xFF000000)>>24))
+#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)
+{
+	short w, h, x, y;
+	u_int *s, *d;
+
+	if ((destSize[0] == srcSize[0] && destSize[1] == srcSize[1]) || !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)
+		{
+			s = source + y*srcSize[0];
+			d = dest + y*destSize[0];
+			for (x = 0; x < w; ++x, ++s, ++d)
+				CONV_PIXEL(*d, *s);
+		}
+	}
+	else
+	{
+		// here we scale
+		// interpolation accumulator
+		int accHeight = srcSize[1] >> 1;
+		d = dest;
+		s = source;
+		// process image rows
+		for (y = 0; y < srcSize[1]; ++y)
+		{
+			// increase height accum
+			accHeight += destSize[1];
+			// if pixel row has to be drawn
+			if (accHeight >= srcSize[1])
+			{
+				// decrease accum
+				accHeight -= srcSize[1];
+				// width accum
+				int accWidth = srcSize[0] >> 1;
+				// process row
+				for (x = 0; x < srcSize[0]; ++x, ++s)
+				{
+					// increase width accum
+					accWidth += destSize[0];
+					// if pixel has to be drawn
+					if (accWidth >= srcSize[0])
+					{
+						// decrease accum
+						accWidth -= srcSize[0];
+						// convert pixel
+						CONV_PIXEL(*d, *s);
+						// next pixel
+						++d;
+					}
+				}
+			}
+			// if pixel row will not be drawn
+			else
+				// move source pointer to next row
+				s += srcSize[0];
+		}
+	}
+}
 
 // DeckLink object allocation
 static PyObject *DeckLink_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -64,8 +269,9 @@ static PyObject *DeckLink_new(PyTypeObject *type, PyObject *args, PyObject *kwds
 	// allocate object
 	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;
-	self->m_lastClock = 0.0;
 	// return allocated object
 	return reinterpret_cast<PyObject*>(self);
 }
@@ -89,14 +295,30 @@ static void DeckLink_dealloc(DeckLink *self)
 }
 
 
-ExceptionID AutoDetectionNotAvail;
+ExceptionID AutoDetectionNotAvail, DeckLinkOpenCard, DeckLinkBadFormat, DeckLinkInternalError;
 ExpDesc AutoDetectionNotAvailDesc(AutoDetectionNotAvail, "Auto detection not yet available");
+ExpDesc DeckLinkOpenCardDesc(DeckLinkOpenCard, "Cannot open card for output");
+ExpDesc DeckLinkBadFormatDesc(DeckLinkBadFormat, "Invalid or unsupported output format, use <mode>[/3D]");
+ExpDesc DeckLinkInternalErrorDesc(DeckLinkInternalError, "DeckLink API internal error, please report");
 
 // DeckLink object initialization
 static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds)
 {
-	// parameters - game object with video texture
-	PyObject *obj = NULL;
+	IDeckLinkIterator*				pIterator;
+	IDeckLinkAttributes*			pAttributes;
+	IDeckLinkDisplayModeIterator*	pDisplayModeIterator;
+	IDeckLinkDisplayMode*			pDisplayMode;
+	IDeckLink*						pDL;
+	char*							p3D;
+	BOOL							flag;
+	size_t							len;
+	int								i;
+	u_int							displayFlags;
+	BMDVideoOutputFlags				outputFlags;
+	BMDDisplayModeSupport			support;
+	u_int*							bytes;
+
+
 	// material ID
 	short cardIdx = 0;
 	// texture ID
@@ -107,11 +329,107 @@ static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds)
 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|hs",
 		const_cast<char**>(kwlist), &cardIdx, &format))
 		return -1; 
-
 	
-	if (format == NULL)
+	try
 	{
-		THRWEXCP(AutoDetectionNotAvail, S_OK);
+		if (format == NULL)
+		{
+			THRWEXCP(AutoDetectionNotAvail, S_OK);
+		}
+
+		if ((p3D = strchr(format, '/')) != NULL && strcmp(p3D, "/3D"))
+			THRWEXCP(DeckLinkBadFormat, S_OK);
+		self->mUse3D = (p3D) ? true : false;
+		// read the mode
+		len = (p3D) ? (size_t)(p3D - format) : strlen(format);
+		// throws if bad mode
+		decklink_ReadDisplayMode(format, len, &self->mDisplayMode);
+
+		pIterator = BMD_CreateDeckLinkIterator();
+		pDL = NULL;
+		if (pIterator)
+		{
+			i = 0;
+			while (pIterator->Next(&pDL) == S_OK)
+			{
+				if (i == cardIdx)
+				{
+					break;
+				}
+				i++;
+				pDL->Release();
+				pDL = NULL;
+			}
+			pIterator->Release();
+		}
+
+		if (!pDL)
+		{
+			THRWEXCP(DeckLinkOpenCard, S_OK);
+		}
+		// detect the capabilities
+		if (pDL->QueryInterface(IID_IDeckLinkAttributes, (void**)&pAttributes) == S_OK)
+		{
+			if (pAttributes->GetFlag(BMDDeckLinkSupportsInternalKeying, &flag) == S_OK && flag)
+			{
+				self->mKeyingSupported = true;
+				if (pAttributes->GetFlag(BMDDeckLinkSupportsHDKeying, &flag) == S_OK && flag)
+					self->mHDKeyingSupported = true;
+			}
+			pAttributes->Release();
+		}
+
+		if (pDL->QueryInterface(IID_IDeckLinkOutput, (void**)&self->mDLOutput) != S_OK)
+			self->mDLOutput = NULL;
+		if (self->mKeyingSupported)
+			pDL->QueryInterface(IID_IDeckLinkKeyer, (void **)&self->mKeyer);
+		// we don't need the device anymore, release to avoid leaking
+		pDL->Release();
+
+		if (!self->mDLOutput)
+			THRWEXCP(DeckLinkOpenCard, S_OK);
+
+		if (self->mDLOutput->GetDisplayModeIterator(&pDisplayModeIterator) != S_OK)
+			THRWEXCP(DeckLinkInternalError, S_OK);
+
+		displayFlags = (self->mUse3D) ? bmdDisplayModeSupports3D : 0;
+		outputFlags = (self->mUse3D) ? bmdVideoOutputDualStream3D : bmdVideoOutputFlagDefault;
+		pDisplayMode = NULL;
+		while (pDisplayModeIterator->Next(&pDisplayMode) == S_OK)
+		{
+			if (pDisplayMode->GetDisplayMode() == self->mDisplayMode
+				&& (pDisplayMode->GetFlags() & displayFlags) == displayFlags
+				&& self->mDLOutput->DoesSupportVideoMode(self->mDisplayMode, bmdFormat8BitARGB, outputFlags, &support, NULL) == S_OK
+				&& (support == bmdDisplayModeSupported || support == bmdDisplayModeSupportedWithConversion))
+			{
+				break;
+			}
+			pDisplayMode->Relea

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list