VideoDeckLink.cpp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * The Original Code is Copyright (C) 2015, Blender Foundation
  19. * All rights reserved.
  20. *
  21. * The Original Code is: all of this file.
  22. *
  23. * Contributor(s): Blender Foundation.
  24. *
  25. * ***** END GPL LICENSE BLOCK *****
  26. */
  27. /** \file gameengine/VideoTexture/VideoDeckLink.cpp
  28. * \ingroup bgevideotex
  29. */
  30. #ifdef WITH_GAMEENGINE_DECKLINK
  31. // FFmpeg defines its own version of stdint.h on Windows.
  32. // Decklink needs FFmpeg, so it uses its version of stdint.h
  33. // this is necessary for INT64_C macro
  34. #ifndef __STDC_CONSTANT_MACROS
  35. #define __STDC_CONSTANT_MACROS
  36. #endif
  37. // this is necessary for UINTPTR_MAX (used by atomic-ops)
  38. #ifndef __STDC_LIMIT_MACROS
  39. #define __STDC_LIMIT_MACROS
  40. #ifdef __STDC_LIMIT_MACROS /* else it may be unused */
  41. #endif
  42. #endif
  43. #include <stdint.h>
  44. #include <string.h>
  45. #ifndef WIN32
  46. #include <sys/time.h>
  47. #include <sys/resource.h>
  48. #include <sys/mman.h>
  49. #endif
  50. #include "atomic_ops.h"
  51. #include "MEM_guardedalloc.h"
  52. #include "PIL_time.h"
  53. #include "VideoDeckLink.h"
  54. #include "DeckLink.h"
  55. #include "Exception.h"
  56. #include "KX_KetsjiEngine.h"
  57. #include "KX_PythonInit.h"
  58. extern ExceptionID DeckLinkInternalError;
  59. ExceptionID SourceVideoOnlyCapture, VideoDeckLinkBadFormat, VideoDeckLinkOpenCard, VideoDeckLinkDvpInternalError, VideoDeckLinkPinMemoryError;
  60. ExpDesc SourceVideoOnlyCaptureDesc(SourceVideoOnlyCapture, "This video source only allows live capture");
  61. ExpDesc VideoDeckLinkBadFormatDesc(VideoDeckLinkBadFormat, "Invalid or unsupported capture format, should be <mode>/<pixel>[/3D]");
  62. ExpDesc VideoDeckLinkOpenCardDesc(VideoDeckLinkOpenCard, "Cannot open capture card, check if driver installed");
  63. ExpDesc VideoDeckLinkDvpInternalErrorDesc(VideoDeckLinkDvpInternalError, "DVP API internal error, please report");
  64. ExpDesc VideoDeckLinkPinMemoryErrorDesc(VideoDeckLinkPinMemoryError, "Error pinning memory");
  65. #ifdef WIN32
  66. ////////////////////////////////////////////
  67. // SynInfo
  68. //
  69. // Sets up a semaphore which is shared between the GPU and CPU and used to
  70. // synchronise access to DVP buffers.
  71. #define DVP_CHECK(cmd) if ((cmd) != DVP_STATUS_OK) THRWEXCP(VideoDeckLinkDvpInternalError, S_OK)
  72. struct SyncInfo
  73. {
  74. SyncInfo(uint32_t semaphoreAllocSize, uint32_t semaphoreAddrAlignment)
  75. {
  76. mSemUnaligned = (uint32_t*)malloc(semaphoreAllocSize + semaphoreAddrAlignment - 1);
  77. // Apply alignment constraints
  78. uint64_t val = (uint64_t)mSemUnaligned;
  79. val += semaphoreAddrAlignment - 1;
  80. val &= ~((uint64_t)semaphoreAddrAlignment - 1);
  81. mSem = (uint32_t*)val;
  82. // Initialise
  83. mSem[0] = 0;
  84. mReleaseValue = 0;
  85. mAcquireValue = 0;
  86. // Setup DVP sync object and import it
  87. DVPSyncObjectDesc syncObjectDesc;
  88. syncObjectDesc.externalClientWaitFunc = NULL;
  89. syncObjectDesc.sem = (uint32_t*)mSem;
  90. DVP_CHECK(dvpImportSyncObject(&syncObjectDesc, &mDvpSync));
  91. }
  92. ~SyncInfo()
  93. {
  94. dvpFreeSyncObject(mDvpSync);
  95. free((void*)mSemUnaligned);
  96. }
  97. volatile uint32_t* mSem;
  98. volatile uint32_t* mSemUnaligned;
  99. volatile uint32_t mReleaseValue;
  100. volatile uint32_t mAcquireValue;
  101. DVPSyncObjectHandle mDvpSync;
  102. };
  103. ////////////////////////////////////////////
  104. // TextureTransferDvp: transfer with GPUDirect
  105. ////////////////////////////////////////////
  106. class TextureTransferDvp : public TextureTransfer
  107. {
  108. public:
  109. TextureTransferDvp(DVPBufferHandle dvpTextureHandle, TextureDesc *pDesc, void *address, uint32_t allocatedSize)
  110. {
  111. DVPSysmemBufferDesc sysMemBuffersDesc;
  112. mExtSync = NULL;
  113. mGpuSync = NULL;
  114. mDvpSysMemHandle = 0;
  115. mDvpTextureHandle = 0;
  116. mTextureHeight = 0;
  117. mAllocatedSize = 0;
  118. mBuffer = NULL;
  119. if (!_PinBuffer(address, allocatedSize))
  120. THRWEXCP(VideoDeckLinkPinMemoryError, S_OK);
  121. mAllocatedSize = allocatedSize;
  122. mBuffer = address;
  123. try {
  124. if (!mBufferAddrAlignment) {
  125. DVP_CHECK(dvpGetRequiredConstantsGLCtx(&mBufferAddrAlignment, &mBufferGpuStrideAlignment,
  126. &mSemaphoreAddrAlignment, &mSemaphoreAllocSize,
  127. &mSemaphorePayloadOffset, &mSemaphorePayloadSize));
  128. }
  129. mExtSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment);
  130. mGpuSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment);
  131. sysMemBuffersDesc.width = pDesc->width;
  132. sysMemBuffersDesc.height = pDesc->height;
  133. sysMemBuffersDesc.stride = pDesc->stride;
  134. switch (pDesc->format) {
  135. case GL_RED_INTEGER:
  136. sysMemBuffersDesc.format = DVP_RED_INTEGER;
  137. break;
  138. default:
  139. sysMemBuffersDesc.format = DVP_BGRA;
  140. break;
  141. }
  142. switch (pDesc->type) {
  143. case GL_UNSIGNED_BYTE:
  144. sysMemBuffersDesc.type = DVP_UNSIGNED_BYTE;
  145. break;
  146. case GL_UNSIGNED_INT_2_10_10_10_REV:
  147. sysMemBuffersDesc.type = DVP_UNSIGNED_INT_2_10_10_10_REV;
  148. break;
  149. case GL_UNSIGNED_INT_8_8_8_8:
  150. sysMemBuffersDesc.type = DVP_UNSIGNED_INT_8_8_8_8;
  151. break;
  152. case GL_UNSIGNED_INT_10_10_10_2:
  153. sysMemBuffersDesc.type = DVP_UNSIGNED_INT_10_10_10_2;
  154. break;
  155. default:
  156. sysMemBuffersDesc.type = DVP_UNSIGNED_INT;
  157. break;
  158. }
  159. sysMemBuffersDesc.size = pDesc->width * pDesc->height * 4;
  160. sysMemBuffersDesc.bufAddr = mBuffer;
  161. DVP_CHECK(dvpCreateBuffer(&sysMemBuffersDesc, &mDvpSysMemHandle));
  162. DVP_CHECK(dvpBindToGLCtx(mDvpSysMemHandle));
  163. mDvpTextureHandle = dvpTextureHandle;
  164. mTextureHeight = pDesc->height;
  165. }
  166. catch (Exception &) {
  167. clean();
  168. throw;
  169. }
  170. }
  171. ~TextureTransferDvp()
  172. {
  173. clean();
  174. }
  175. virtual void PerformTransfer()
  176. {
  177. // perform the transfer
  178. // tell DVP that the old texture buffer will no longer be used
  179. dvpMapBufferEndAPI(mDvpTextureHandle);
  180. // do we need this?
  181. mGpuSync->mReleaseValue++;
  182. dvpBegin();
  183. // Copy from system memory to GPU texture
  184. dvpMapBufferWaitDVP(mDvpTextureHandle);
  185. dvpMemcpyLined(mDvpSysMemHandle, mExtSync->mDvpSync, mExtSync->mAcquireValue, DVP_TIMEOUT_IGNORED,
  186. mDvpTextureHandle, mGpuSync->mDvpSync, mGpuSync->mReleaseValue, 0, mTextureHeight);
  187. dvpMapBufferEndDVP(mDvpTextureHandle);
  188. dvpEnd();
  189. dvpMapBufferWaitAPI(mDvpTextureHandle);
  190. // the transfer is now complete and the texture is ready for use
  191. }
  192. private:
  193. static uint32_t mBufferAddrAlignment;
  194. static uint32_t mBufferGpuStrideAlignment;
  195. static uint32_t mSemaphoreAddrAlignment;
  196. static uint32_t mSemaphoreAllocSize;
  197. static uint32_t mSemaphorePayloadOffset;
  198. static uint32_t mSemaphorePayloadSize;
  199. void clean()
  200. {
  201. if (mDvpSysMemHandle) {
  202. dvpUnbindFromGLCtx(mDvpSysMemHandle);
  203. dvpDestroyBuffer(mDvpSysMemHandle);
  204. }
  205. if (mExtSync)
  206. delete mExtSync;
  207. if (mGpuSync)
  208. delete mGpuSync;
  209. if (mBuffer)
  210. _UnpinBuffer(mBuffer, mAllocatedSize);
  211. }
  212. SyncInfo* mExtSync;
  213. SyncInfo* mGpuSync;
  214. DVPBufferHandle mDvpSysMemHandle;
  215. DVPBufferHandle mDvpTextureHandle;
  216. uint32_t mTextureHeight;
  217. uint32_t mAllocatedSize;
  218. void* mBuffer;
  219. };
  220. uint32_t TextureTransferDvp::mBufferAddrAlignment;
  221. uint32_t TextureTransferDvp::mBufferGpuStrideAlignment;
  222. uint32_t TextureTransferDvp::mSemaphoreAddrAlignment;
  223. uint32_t TextureTransferDvp::mSemaphoreAllocSize;
  224. uint32_t TextureTransferDvp::mSemaphorePayloadOffset;
  225. uint32_t TextureTransferDvp::mSemaphorePayloadSize;
  226. #endif
  227. ////////////////////////////////////////////
  228. // TextureTransferOGL: transfer using standard OGL buffers
  229. ////////////////////////////////////////////
  230. class TextureTransferOGL : public TextureTransfer
  231. {
  232. public:
  233. TextureTransferOGL(GLuint texId, TextureDesc *pDesc, void *address)
  234. {
  235. memcpy(&mDesc, pDesc, sizeof(mDesc));
  236. mTexId = texId;
  237. mBuffer = address;
  238. // as we cache transfer object, we will create one texture to hold the buffer
  239. glGenBuffers(1, &mUnpinnedTextureBuffer);
  240. // create a storage for it
  241. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
  242. glBufferData(GL_PIXEL_UNPACK_BUFFER, pDesc->size, NULL, GL_DYNAMIC_DRAW);
  243. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  244. }
  245. ~TextureTransferOGL()
  246. {
  247. glDeleteBuffers(1, &mUnpinnedTextureBuffer);
  248. }
  249. virtual void PerformTransfer()
  250. {
  251. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer);
  252. glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, mDesc.size, mBuffer);
  253. glBindTexture(GL_TEXTURE_2D, mTexId);
  254. // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data
  255. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL);
  256. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  257. }
  258. private:
  259. // intermediate texture to receive the buffer
  260. GLuint mUnpinnedTextureBuffer;
  261. // target texture to receive the image
  262. GLuint mTexId;
  263. // buffer
  264. void *mBuffer;
  265. // characteristic of the image
  266. TextureDesc mDesc;
  267. };
  268. ////////////////////////////////////////////
  269. // TextureTransferPMB: transfer using pinned memory buffer
  270. ////////////////////////////////////////////
  271. class TextureTransferPMD : public TextureTransfer
  272. {
  273. public:
  274. TextureTransferPMD(GLuint texId, TextureDesc *pDesc, void *address, uint32_t allocatedSize)
  275. {
  276. memcpy(&mDesc, pDesc, sizeof(mDesc));
  277. mTexId = texId;
  278. mBuffer = address;
  279. mAllocatedSize = allocatedSize;
  280. _PinBuffer(address, allocatedSize);
  281. // as we cache transfer object, we will create one texture to hold the buffer
  282. glGenBuffers(1, &mPinnedTextureBuffer);
  283. // create a storage for it
  284. glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, mPinnedTextureBuffer);
  285. glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, pDesc->size, address, GL_STREAM_DRAW);
  286. glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
  287. }
  288. ~TextureTransferPMD()
  289. {
  290. glDeleteBuffers(1, &mPinnedTextureBuffer);
  291. if (mBuffer)
  292. _UnpinBuffer(mBuffer, mAllocatedSize);
  293. }
  294. virtual void PerformTransfer()
  295. {
  296. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPinnedTextureBuffer);
  297. glBindTexture(GL_TEXTURE_2D, mTexId);
  298. // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data
  299. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL);
  300. // wait for the trasnfer to complete
  301. GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
  302. glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 40 * 1000 * 1000); // timeout in nanosec
  303. glDeleteSync(fence);
  304. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  305. }
  306. private:
  307. // intermediate texture to receive the buffer
  308. GLuint mPinnedTextureBuffer;
  309. // target texture to receive the image
  310. GLuint mTexId;
  311. // buffer
  312. void *mBuffer;
  313. // the allocated size
  314. uint32_t mAllocatedSize;
  315. // characteristic of the image
  316. TextureDesc mDesc;
  317. };
  318. bool TextureTransfer::_PinBuffer(void *address, uint32_t size)
  319. {
  320. #ifdef WIN32
  321. return VirtualLock(address, size);
  322. #elif defined(_POSIX_MEMLOCK_RANGE)
  323. return !mlock(address, size);
  324. #endif
  325. }
  326. void TextureTransfer::_UnpinBuffer(void* address, uint32_t size)
  327. {
  328. #ifdef WIN32
  329. VirtualUnlock(address, size);
  330. #elif defined(_POSIX_MEMLOCK_RANGE)
  331. munlock(address, size);
  332. #endif
  333. }
  334. ////////////////////////////////////////////
  335. // PinnedMemoryAllocator
  336. ////////////////////////////////////////////
  337. // static members
  338. bool PinnedMemoryAllocator::mGPUDirectInitialized = false;
  339. bool PinnedMemoryAllocator::mHasDvp = false;
  340. bool PinnedMemoryAllocator::mHasAMDPinnedMemory = false;
  341. size_t PinnedMemoryAllocator::mReservedProcessMemory = 0;
  342. bool PinnedMemoryAllocator::ReserveMemory(size_t size)
  343. {
  344. #ifdef WIN32
  345. // Increase the process working set size to allow pinning of memory.
  346. if (size <= mReservedProcessMemory)
  347. return true;
  348. SIZE_T dwMin = 0, dwMax = 0;
  349. HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_QUOTA, FALSE, GetCurrentProcessId());
  350. if (!hProcess)
  351. return false;
  352. // Retrieve the working set size of the process.
  353. if (!dwMin && !GetProcessWorkingSetSize(hProcess, &dwMin, &dwMax))
  354. return false;
  355. BOOL res = SetProcessWorkingSetSize(hProcess, (size - mReservedProcessMemory) + dwMin, (size - mReservedProcessMemory) + dwMax);
  356. if (!res)
  357. return false;
  358. mReservedProcessMemory = size;
  359. CloseHandle(hProcess);
  360. return true;
  361. #else
  362. struct rlimit rlim;
  363. if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
  364. if (rlim.rlim_cur < size) {
  365. if (rlim.rlim_max < size)
  366. rlim.rlim_max = size;
  367. rlim.rlim_cur = size;
  368. return !setrlimit(RLIMIT_MEMLOCK, &rlim);
  369. }
  370. }
  371. return false;
  372. #endif
  373. }
  374. PinnedMemoryAllocator::PinnedMemoryAllocator(unsigned cacheSize, size_t memSize) :
  375. mRefCount(1U),
  376. #ifdef WIN32
  377. mDvpCaptureTextureHandle(0),
  378. #endif
  379. mTexId(0),
  380. mBufferCacheSize(cacheSize)
  381. {
  382. pthread_mutex_init(&mMutex, NULL);
  383. // do it once
  384. if (!mGPUDirectInitialized) {
  385. #ifdef WIN32
  386. // In windows, AMD_pinned_memory option is not available,
  387. // we must use special DVP API only available for Quadro cards
  388. const char* renderer = (const char *)glGetString(GL_RENDERER);
  389. mHasDvp = (strstr(renderer, "Quadro") != NULL);
  390. if (mHasDvp) {
  391. // In case the DLL is not in place, don't fail, just fallback on OpenGL
  392. if (dvpInitGLContext(DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT) != DVP_STATUS_OK) {
  393. printf("Warning: Could not initialize DVP context, fallback on OpenGL transfer.\nInstall dvp.dll to take advantage of nVidia GPUDirect.\n");
  394. mHasDvp = false;
  395. }
  396. }
  397. #endif
  398. if (GLEW_AMD_pinned_memory)
  399. mHasAMDPinnedMemory = true;
  400. mGPUDirectInitialized = true;
  401. }
  402. if (mHasDvp || mHasAMDPinnedMemory) {
  403. ReserveMemory(memSize);
  404. }
  405. }
  406. PinnedMemoryAllocator::~PinnedMemoryAllocator()
  407. {
  408. void *address;
  409. // first clean the cache if not already done
  410. while (!mBufferCache.empty()) {
  411. address = mBufferCache.back();
  412. mBufferCache.pop_back();
  413. _ReleaseBuffer(address);
  414. }
  415. // clean preallocated buffers
  416. while (!mAllocatedSize.empty()) {
  417. address = mAllocatedSize.begin()->first;
  418. _ReleaseBuffer(address);
  419. }
  420. #ifdef WIN32
  421. if (mDvpCaptureTextureHandle)
  422. dvpDestroyBuffer(mDvpCaptureTextureHandle);
  423. #endif
  424. }
  425. void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId)
  426. {
  427. uint32_t allocatedSize = 0;
  428. TextureTransfer *pTransfer = NULL;
  429. Lock();
  430. if (mAllocatedSize.count(address) > 0)
  431. allocatedSize = mAllocatedSize[address];
  432. Unlock();
  433. if (!allocatedSize)
  434. // internal error!!
  435. return;
  436. if (mTexId != texId)
  437. {
  438. // first time we try to send data to the GPU, allocate a buffer for the texture
  439. glBindTexture(GL_TEXTURE_2D, texId);
  440. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  441. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  442. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  443. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  444. glTexImage2D(GL_TEXTURE_2D, 0, texDesc->internalFormat, texDesc->width, texDesc->height, 0, texDesc->format, texDesc->type, NULL);
  445. glBindTexture(GL_TEXTURE_2D, 0);
  446. mTexId = texId;
  447. }
  448. #ifdef WIN32
  449. if (mHasDvp)
  450. {
  451. if (!mDvpCaptureTextureHandle)
  452. {
  453. // bind DVP to the OGL texture
  454. DVP_CHECK(dvpCreateGPUTextureGL(texId, &mDvpCaptureTextureHandle));
  455. }
  456. }
  457. #endif
  458. Lock();
  459. if (mPinnedBuffer.count(address) > 0)
  460. {
  461. pTransfer = mPinnedBuffer[address];
  462. }
  463. Unlock();
  464. if (!pTransfer)
  465. {
  466. #ifdef WIN32
  467. if (mHasDvp)
  468. pTransfer = new TextureTransferDvp(mDvpCaptureTextureHandle, texDesc, address, allocatedSize);
  469. else
  470. #endif
  471. if (mHasAMDPinnedMemory) {
  472. pTransfer = new TextureTransferPMD(texId, texDesc, address, allocatedSize);
  473. }
  474. else {
  475. pTransfer = new TextureTransferOGL(texId, texDesc, address);
  476. }
  477. if (pTransfer)
  478. {
  479. Lock();
  480. mPinnedBuffer[address] = pTransfer;
  481. Unlock();
  482. }
  483. }
  484. if (pTransfer)
  485. pTransfer->PerformTransfer();
  486. }
  487. // IUnknown methods
  488. HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/, LPVOID* /*ppv*/)
  489. {
  490. return E_NOTIMPL;
  491. }
  492. ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void)
  493. {
  494. return atomic_add_and_fetch_uint32(&mRefCount, 1U);
  495. }
  496. ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void)
  497. {
  498. uint32_t newCount = atomic_sub_and_fetch_uint32(&mRefCount, 1U);
  499. if (newCount == 0)
  500. delete this;
  501. return (ULONG)newCount;
  502. }
  503. // IDeckLinkMemoryAllocator methods
  504. HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer)
  505. {
  506. Lock();
  507. if (mBufferCache.empty())
  508. {
  509. // Allocate memory on a page boundary
  510. // Note: aligned alloc exist in Blender but only for small alignment, use direct allocation then.
  511. // Note: the DeckLink API tries to allocate up to 65 buffer in advance, we will limit this to 3
  512. // because we don't need any caching
  513. if (mAllocatedSize.size() >= mBufferCacheSize)
  514. *allocatedBuffer = NULL;
  515. else {
  516. #ifdef WIN32
  517. *allocatedBuffer = VirtualAlloc(NULL, bufferSize, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE);
  518. #else
  519. if (posix_memalign(allocatedBuffer, 4096, bufferSize) != 0)
  520. *allocatedBuffer = NULL;
  521. #endif
  522. mAllocatedSize[*allocatedBuffer] = bufferSize;
  523. }
  524. }
  525. else {
  526. // Re-use most recently ReleaseBuffer'd address
  527. *allocatedBuffer = mBufferCache.back();
  528. mBufferCache.pop_back();
  529. }
  530. Unlock();
  531. return (*allocatedBuffer) ? S_OK : E_OUTOFMEMORY;
  532. }
  533. HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::ReleaseBuffer(void* buffer)
  534. {
  535. HRESULT result = S_OK;
  536. Lock();
  537. if (mBufferCache.size() < mBufferCacheSize) {
  538. mBufferCache.push_back(buffer);
  539. }
  540. else {
  541. result = _ReleaseBuffer(buffer);
  542. }
  543. Unlock();
  544. return result;
  545. }
  546. HRESULT PinnedMemoryAllocator::_ReleaseBuffer(void* buffer)
  547. {
  548. TextureTransfer *pTransfer;
  549. if (mAllocatedSize.count(buffer) == 0) {
  550. // Internal error!!
  551. return S_OK;
  552. }
  553. else {
  554. // No room left in cache, so un-pin (if it was pinned) and free this buffer
  555. if (mPinnedBuffer.count(buffer) > 0) {
  556. pTransfer = mPinnedBuffer[buffer];
  557. mPinnedBuffer.erase(buffer);
  558. delete pTransfer;
  559. }
  560. #ifdef WIN32
  561. VirtualFree(buffer, 0, MEM_RELEASE);
  562. #else
  563. free(buffer);
  564. #endif
  565. mAllocatedSize.erase(buffer);
  566. }
  567. return S_OK;
  568. }
  569. HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Commit()
  570. {
  571. return S_OK;
  572. }
  573. HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Decommit()
  574. {
  575. void *buffer;
  576. Lock();
  577. while (!mBufferCache.empty()) {
  578. // Cleanup any frames allocated and pinned in AllocateBuffer() but not freed in ReleaseBuffer()
  579. buffer = mBufferCache.back();
  580. mBufferCache.pop_back();
  581. _ReleaseBuffer(buffer);
  582. }
  583. Unlock();
  584. return S_OK;
  585. }
  586. ////////////////////////////////////////////
  587. // Capture Delegate Class
  588. ////////////////////////////////////////////
  589. CaptureDelegate::CaptureDelegate(VideoDeckLink* pOwner) : mpOwner(pOwner)
  590. {
  591. }
  592. HRESULT CaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* inputFrame, IDeckLinkAudioInputPacket* /*audioPacket*/)
  593. {
  594. if (!inputFrame) {
  595. // It's possible to receive a NULL inputFrame, but a valid audioPacket. Ignore audio-only frame.
  596. return S_OK;
  597. }
  598. if ((inputFrame->GetFlags() & bmdFrameHasNoInputSource) == bmdFrameHasNoInputSource) {
  599. // let's not bother transferring frames if there is no source
  600. return S_OK;
  601. }
  602. mpOwner->VideoFrameArrived(inputFrame);
  603. return S_OK;
  604. }
  605. HRESULT CaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags)
  606. {
  607. return S_OK;
  608. }
  609. // macro for exception handling and logging
  610. #define CATCH_EXCP catch (Exception & exp) \
  611. { exp.report(); m_status = SourceError; }
  612. // class VideoDeckLink
  613. // constructor
  614. VideoDeckLink::VideoDeckLink (HRESULT * hRslt) : VideoBase(),
  615. mDLInput(NULL),
  616. mUse3D(false),
  617. mFrameWidth(0),
  618. mFrameHeight(0),
  619. mpAllocator(NULL),
  620. mpCaptureDelegate(NULL),
  621. mpCacheFrame(NULL),
  622. mClosing(false)
  623. {
  624. mDisplayMode = (BMDDisplayMode)0;
  625. mPixelFormat = (BMDPixelFormat)0;
  626. pthread_mutex_init(&mCacheMutex, NULL);
  627. }
  628. // destructor
  629. VideoDeckLink::~VideoDeckLink ()
  630. {
  631. LockCache();
  632. mClosing = true;
  633. if (mpCacheFrame)
  634. {
  635. mpCacheFrame->Release();
  636. mpCacheFrame = NULL;
  637. }
  638. UnlockCache();
  639. if (mDLInput != NULL)
  640. {
  641. // Cleanup for Capture
  642. mDLInput->StopStreams();
  643. mDLInput->SetCallback(NULL);
  644. mDLInput->DisableVideoInput();
  645. mDLInput->DisableAudioInput();
  646. mDLInput->FlushStreams();
  647. if (mDLInput->Release() != 0) {
  648. printf("Reference count not NULL on DeckLink device when closing it, please report!\n");
  649. }
  650. mDLInput = NULL;
  651. }
  652. if (mpAllocator)
  653. {
  654. // if the device was properly cleared, this should be 0
  655. if (mpAllocator->Release() != 0) {
  656. printf("Reference count not NULL on Allocator when closing it, please report!\n");
  657. }
  658. mpAllocator = NULL;
  659. }
  660. if (mpCaptureDelegate)
  661. {
  662. delete mpCaptureDelegate;
  663. mpCaptureDelegate = NULL;
  664. }
  665. }
  666. void VideoDeckLink::refresh(void)
  667. {
  668. m_avail = false;
  669. }
  670. // release components
  671. bool VideoDeckLink::release()
  672. {
  673. // release
  674. return true;
  675. }
  676. // open video file
  677. void VideoDeckLink::openFile (char *filename)
  678. {
  679. // only live capture on this device
  680. THRWEXCP(SourceVideoOnlyCapture, S_OK);
  681. }
  682. // open video capture device
  683. void VideoDeckLink::openCam (char *format, short camIdx)
  684. {
  685. IDeckLinkDisplayModeIterator* pDLDisplayModeIterator;
  686. BMDDisplayModeSupport modeSupport;
  687. IDeckLinkDisplayMode* pDLDisplayMode;
  688. IDeckLinkIterator* pIterator;
  689. BMDTimeValue frameDuration;
  690. BMDTimeScale frameTimescale;
  691. IDeckLink* pDL;
  692. uint32_t displayFlags, inputFlags;
  693. char *pPixel, *p3D, *pEnd, *pSize;
  694. size_t len;
  695. int i, modeIdx, cacheSize;
  696. // format is constructed as <displayMode>/<pixelFormat>[/3D][:<cacheSize>]
  697. // <displayMode> takes the form of BMDDisplayMode identifier minus the 'bmdMode' prefix.
  698. // This implementation understands all the modes defined in SDK 10.3.1 but you can alternatively
  699. // use the 4 characters internal representation of the mode (e.g. 'HD1080p24' == '24ps')
  700. // <pixelFormat> takes the form of BMDPixelFormat identifier minus the 'bmdFormat' prefix.
  701. // This implementation understand all the formats defined in SDK 10.32.1 but you can alternatively
  702. // use the 4 characters internal representation of the format (e.g. '10BitRGB' == 'r210')
  703. // Not all combinations of mode and pixel format are possible and it also depends on the card!
  704. // Use /3D postfix if you are capturing a 3D stream with frame packing
  705. // Example: To capture FullHD 1920x1080@24Hz with 3D packing and 4:4:4 10 bits RGB pixel format, use
  706. // "HD1080p24/10BitRGB/3D" (same as "24ps/r210/3D")
  707. // (this will be the normal capture format for FullHD on the DeckLink 4k extreme)
  708. if ((pSize = strchr(format, ':')) != NULL) {
  709. cacheSize = strtol(pSize+1, &pEnd, 10);
  710. }
  711. else {
  712. cacheSize = 8;
  713. pSize = format + strlen(format);
  714. }
  715. if ((pPixel = strchr(format, '/')) == NULL ||
  716. ((p3D = strchr(pPixel + 1, '/')) != NULL && strncmp(p3D, "/3D", pSize-p3D)))
  717. THRWEXCP(VideoDeckLinkBadFormat, S_OK);
  718. mUse3D = (p3D) ? true : false;
  719. // to simplify pixel format parsing
  720. if (!p3D)
  721. p3D = pSize;
  722. // read the mode
  723. len = (size_t)(pPixel - format);
  724. // accept integer display mode
  725. try {
  726. // throws if bad mode
  727. decklink_ReadDisplayMode(format, len, &mDisplayMode);
  728. // found a valid mode, remember that we do not look for an index
  729. modeIdx = -1;
  730. }
  731. catch (Exception &) {
  732. // accept also purely numerical mode as a mode index
  733. modeIdx = strtol(format, &pEnd, 10);
  734. if (pEnd != pPixel || modeIdx < 0)
  735. // not a pure number, give up
  736. throw;
  737. }
  738. // skip /
  739. pPixel++;
  740. len = (size_t)(p3D - pPixel);
  741. // throws if bad format
  742. decklink_ReadPixelFormat(pPixel, len, &mPixelFormat);
  743. // Caution: DeckLink API used from this point, make sure entity are released before throwing
  744. // open the card
  745. pIterator = BMD_CreateDeckLinkIterator();
  746. if (pIterator) {
  747. i = 0;
  748. while (pIterator->Next(&pDL) == S_OK) {
  749. if (i == camIdx) {
  750. if (pDL->QueryInterface(IID_IDeckLinkInput, (void**)&mDLInput) != S_OK)
  751. mDLInput = NULL;
  752. pDL->Release();
  753. break;
  754. }
  755. i++;
  756. pDL->Release();
  757. }
  758. pIterator->Release();
  759. }
  760. if (!mDLInput)
  761. THRWEXCP(VideoDeckLinkOpenCard, S_OK);
  762. // check if display mode and pixel format are supported
  763. if (mDLInput->GetDisplayModeIterator(&pDLDisplayModeIterator) != S_OK)
  764. THRWEXCP(DeckLinkInternalError, S_OK);
  765. pDLDisplayMode = NULL;
  766. displayFlags = (mUse3D) ? bmdDisplayModeSupports3D : 0;
  767. inputFlags = (mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault;
  768. while (pDLDisplayModeIterator->Next(&pDLDisplayMode) == S_OK)
  769. {
  770. if (modeIdx == 0 || pDLDisplayMode->GetDisplayMode() == mDisplayMode) {
  771. // in case we get here because of modeIdx, make sure we have mDisplayMode set
  772. mDisplayMode = pDLDisplayMode->GetDisplayMode();
  773. if ((pDLDisplayMode->GetFlags() & displayFlags) == displayFlags &&
  774. mDLInput->DoesSupportVideoMode(mDisplayMode, mPixelFormat, inputFlags, &modeSupport, NULL) == S_OK &&
  775. modeSupport == bmdDisplayModeSupported)
  776. {
  777. break;
  778. }
  779. }
  780. pDLDisplayMode->Release();
  781. pDLDisplayMode = NULL;
  782. if (modeIdx-- == 0) {
  783. // reached the correct mode index but it does not meet the pixel format, give up
  784. break;
  785. }
  786. }
  787. pDLDisplayModeIterator->Release();
  788. if (pDLDisplayMode == NULL)
  789. THRWEXCP(VideoDeckLinkBadFormat, S_OK);
  790. mFrameWidth = pDLDisplayMode->GetWidth();
  791. mFrameHeight = pDLDisplayMode->GetHeight();
  792. mTextureDesc.height = (mUse3D) ? 2 * mFrameHeight : mFrameHeight;
  793. pDLDisplayMode->GetFrameRate(&frameDuration, &frameTimescale);
  794. pDLDisplayMode->Release();
  795. // for information, in case the application wants to know
  796. m_size[0] = mFrameWidth;
  797. m_size[1] = mTextureDesc.height;
  798. m_frameRate = (float)frameTimescale / (float)frameDuration;
  799. switch (mPixelFormat)
  800. {
  801. case bmdFormat8BitYUV:
  802. // 2 pixels per word
  803. mTextureDesc.stride = mFrameWidth * 2;
  804. mTextureDesc.width = mFrameWidth / 2;
  805. mTextureDesc.internalFormat = GL_RGBA;
  806. mTextureDesc.format = GL_BGRA;
  807. mTextureDesc.type = GL_UNSIGNED_BYTE;
  808. break;
  809. case bmdFormat10BitYUV:
  810. // 6 pixels in 4 words, rounded to 48 pixels
  811. mTextureDesc.stride = ((mFrameWidth + 47) / 48) * 128;
  812. mTextureDesc.width = mTextureDesc.stride/4;
  813. mTextureDesc.internalFormat = GL_RGB10_A2;
  814. mTextureDesc.format = GL_BGRA;
  815. mTextureDesc.type = GL_UNSIGNED_INT_2_10_10_10_REV;
  816. break;
  817. case bmdFormat8BitARGB:
  818. mTextureDesc.stride = mFrameWidth * 4;
  819. mTextureDesc.width = mFrameWidth;
  820. mTextureDesc.internalFormat = GL_RGBA;
  821. mTextureDesc.format = GL_BGRA;
  822. mTextureDesc.type = GL_UNSIGNED_INT_8_8_8_8;
  823. break;
  824. case bmdFormat8BitBGRA:
  825. mTextureDesc.stride = mFrameWidth * 4;
  826. mTextureDesc.width = mFrameWidth;
  827. mTextureDesc.internalFormat = GL_RGBA;
  828. mTextureDesc.format = GL_BGRA;
  829. mTextureDesc.type = GL_UNSIGNED_BYTE;
  830. break;
  831. case bmdFormat10BitRGBXLE:
  832. // 1 pixel per word, rounded to 64 pixels
  833. mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256;
  834. mTextureDesc.width = mTextureDesc.stride/4;
  835. mTextureDesc.internalFormat = GL_RGB10_A2;
  836. mTextureDesc.format = GL_RGBA;
  837. mTextureDesc.type = GL_UNSIGNED_INT_10_10_10_2;
  838. break;
  839. case bmdFormat10BitRGBX:
  840. case bmdFormat10BitRGB:
  841. // 1 pixel per word, rounded to 64 pixels
  842. mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256;
  843. mTextureDesc.width = mTextureDesc.stride/4;
  844. mTextureDesc.internalFormat = GL_R32UI;
  845. mTextureDesc.format = GL_RED_INTEGER;
  846. mTextureDesc.type = GL_UNSIGNED_INT;
  847. break;
  848. case bmdFormat12BitRGB:
  849. case bmdFormat12BitRGBLE:
  850. // 8 pixels in 9 word
  851. mTextureDesc.stride = (mFrameWidth * 36) / 8;
  852. mTextureDesc.width = mTextureDesc.stride/4;
  853. mTextureDesc.internalFormat = GL_R32UI;
  854. mTextureDesc.format = GL_RED_INTEGER;
  855. mTextureDesc.type = GL_UNSIGNED_INT;
  856. break;
  857. default:
  858. // for unknown pixel format, this will be resolved when a frame arrives
  859. mTextureDesc.format = GL_RED_INTEGER;
  860. mTextureDesc.type = GL_UNSIGNED_INT;
  861. break;
  862. }
  863. // reserve memory for cache frame + 1 to accomodate for pixel format that we don't know yet
  864. // note: we can't use stride as it is not yet known if the pixel format is unknown
  865. // use instead the frame width as in worst case it's not much different (e.g. HD720/10BITYUV: 1296 pixels versus 1280)
  866. // note: some pixel format take more than 4 bytes take that into account (9/8 versus 1)
  867. mpAllocator = new PinnedMemoryAllocator(cacheSize, mFrameWidth*mTextureDesc.height * 4 * (1+cacheSize*9/8));
  868. if (mDLInput->SetVideoInputFrameMemoryAllocator(mpAllocator) != S_OK)
  869. THRWEXCP(DeckLinkInternalError, S_OK);
  870. mpCaptureDelegate = new CaptureDelegate(this);
  871. if (mDLInput->SetCallback(mpCaptureDelegate) != S_OK)
  872. THRWEXCP(DeckLinkInternalError, S_OK);
  873. if (mDLInput->EnableVideoInput(mDisplayMode, mPixelFormat, ((mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault)) != S_OK)
  874. // this shouldn't failed, we tested above
  875. THRWEXCP(DeckLinkInternalError, S_OK);
  876. // just in case it is needed to capture from certain cards, we don't check error because we don't need audio
  877. mDLInput->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2);
  878. // open base class
  879. VideoBase::openCam(format, camIdx);
  880. // ready to capture, will start when application calls play()
  881. }
  882. // play video
  883. bool VideoDeckLink::play (void)
  884. {
  885. try
  886. {
  887. // if object is able to play
  888. if (VideoBase::play())
  889. {
  890. mDLInput->FlushStreams();
  891. return (mDLInput->StartStreams() == S_OK);
  892. }
  893. }
  894. CATCH_EXCP;
  895. return false;
  896. }
  897. // pause video
  898. bool VideoDeckLink::pause (void)
  899. {
  900. try
  901. {
  902. if (VideoBase::pause())
  903. {
  904. mDLInput->PauseStreams();
  905. return true;
  906. }
  907. }
  908. CATCH_EXCP;
  909. return false;
  910. }
  911. // stop video
  912. bool VideoDeckLink::stop (void)
  913. {
  914. try
  915. {
  916. VideoBase::stop();
  917. mDLInput->StopStreams();
  918. return true;
  919. }
  920. CATCH_EXCP;
  921. return false;
  922. }
  923. // set video range
  924. void VideoDeckLink::setRange (double start, double stop)
  925. {
  926. }
  927. // set framerate
  928. void VideoDeckLink::setFrameRate (float rate)
  929. {
  930. }
  931. // image calculation
  932. // send cache frame directly to GPU
  933. void VideoDeckLink::calcImage (unsigned int texId, double ts)
  934. {
  935. IDeckLinkVideoInputFrame* pFrame;
  936. LockCache();
  937. pFrame = mpCacheFrame;
  938. mpCacheFrame = NULL;
  939. UnlockCache();
  940. if (pFrame) {
  941. // BUG: the dvpBindToGLCtx function fails the first time it is used, don't know why.
  942. // This causes an exception to be thrown.
  943. // This should be fixed but in the meantime we will catch the exception because
  944. // it is crucial that we release the frame to keep the reference count right on the DeckLink device
  945. try {
  946. uint32_t rowSize = pFrame->GetRowBytes();
  947. uint32_t textureSize = rowSize * pFrame->GetHeight();
  948. void* videoPixels = NULL;
  949. void* rightEyePixels = NULL;
  950. if (!mTextureDesc.stride) {
  951. // we could not compute the texture size earlier (unknown pixel size)
  952. // let's do it now
  953. mTextureDesc.stride = rowSize;
  954. mTextureDesc.width = mTextureDesc.stride / 4;
  955. }
  956. if (mTextureDesc.stride != rowSize) {
  957. // unexpected frame size, ignore
  958. // TBD: print a warning
  959. }
  960. else {
  961. pFrame->GetBytes(&videoPixels);
  962. if (mUse3D) {
  963. IDeckLinkVideoFrame3DExtensions *if3DExtensions = NULL;
  964. IDeckLinkVideoFrame *rightEyeFrame = NULL;
  965. if (pFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **)&if3DExtensions) == S_OK &&
  966. if3DExtensions->GetFrameForRightEye(&rightEyeFrame) == S_OK) {
  967. rightEyeFrame->GetBytes(&rightEyePixels);
  968. textureSize += ((uint64_t)rightEyePixels - (uint64_t)videoPixels);
  969. }
  970. if (rightEyeFrame)
  971. rightEyeFrame->Release();
  972. if (if3DExtensions)
  973. if3DExtensions->Release();
  974. }
  975. mTextureDesc.size = mTextureDesc.width * mTextureDesc.height * 4;
  976. if (mTextureDesc.size == textureSize) {
  977. // this means that both left and right frame are contiguous and that there is no padding
  978. // do the transfer
  979. mpAllocator->TransferBuffer(videoPixels, &mTextureDesc, texId);
  980. }
  981. }
  982. }
  983. catch (Exception &) {
  984. pFrame->Release();
  985. throw;
  986. }
  987. // this will trigger PinnedMemoryAllocator::RealaseBuffer
  988. pFrame->Release();
  989. }
  990. // currently we don't pass the image to the application
  991. m_avail = false;
  992. }
  993. // A frame is available from the board
  994. // Called from an internal thread, just pass the frame to the main thread
  995. void VideoDeckLink::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame)
  996. {
  997. IDeckLinkVideoInputFrame* pOldFrame = NULL;
  998. LockCache();
  999. if (!mClosing)
  1000. {
  1001. pOldFrame = mpCacheFrame;
  1002. mpCacheFrame = inputFrame;
  1003. inputFrame->AddRef();
  1004. }
  1005. UnlockCache();
  1006. // old frame no longer needed, just release it
  1007. if (pOldFrame)
  1008. pOldFrame->Release();
  1009. }
  1010. // python methods
  1011. // object initialization
  1012. static int VideoDeckLink_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
  1013. {
  1014. static const char *kwlist[] = { "format", "capture", NULL };
  1015. PyImage *self = reinterpret_cast<PyImage*>(pySelf);
  1016. // see openCam for a description of format
  1017. char * format = NULL;
  1018. // capture device number, i.e. DeckLink card number, default first one
  1019. short capt = 0;
  1020. if (!GLEW_VERSION_1_5) {
  1021. PyErr_SetString(PyExc_RuntimeError, "VideoDeckLink requires at least OpenGL 1.5");
  1022. return -1;
  1023. }
  1024. // get parameters
  1025. if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|h",
  1026. const_cast<char**>(kwlist), &format, &capt))
  1027. return -1;
  1028. try {
  1029. // create video object
  1030. Video_init<VideoDeckLink>(self);
  1031. // open video source, control comes back to VideoDeckLink::openCam
  1032. Video_open(getVideo(self), format, capt);
  1033. }
  1034. catch (Exception & exp) {
  1035. exp.report();
  1036. return -1;
  1037. }
  1038. // initialization succeded
  1039. return 0;
  1040. }
  1041. // methods structure
  1042. static PyMethodDef videoMethods[] =
  1043. { // methods from VideoBase class
  1044. {"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"},
  1045. {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"},
  1046. {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"},
  1047. {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"},
  1048. {NULL}
  1049. };
  1050. // attributes structure
  1051. static PyGetSetDef videoGetSets[] =
  1052. { // methods from VideoBase class
  1053. {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
  1054. {(char*)"framerate", (getter)Video_getFrameRate, NULL, (char*)"frame rate", NULL},
  1055. // attributes from ImageBase class
  1056. {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
  1057. {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
  1058. {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
  1059. {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
  1060. {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
  1061. {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
  1062. {NULL}
  1063. };
  1064. // python type declaration
  1065. PyTypeObject VideoDeckLinkType =
  1066. {
  1067. PyVarObject_HEAD_INIT(NULL, 0)
  1068. "VideoTexture.VideoDeckLink", /*tp_name*/
  1069. sizeof(PyImage), /*tp_basicsize*/
  1070. 0, /*tp_itemsize*/
  1071. (destructor)Image_dealloc, /*tp_dealloc*/
  1072. 0, /*tp_print*/
  1073. 0, /*tp_getattr*/
  1074. 0, /*tp_setattr*/
  1075. 0, /*tp_compare*/
  1076. 0, /*tp_repr*/
  1077. 0, /*tp_as_number*/
  1078. 0, /*tp_as_sequence*/
  1079. 0, /*tp_as_mapping*/
  1080. 0, /*tp_hash */
  1081. 0, /*tp_call*/
  1082. 0, /*tp_str*/
  1083. 0, /*tp_getattro*/
  1084. 0, /*tp_setattro*/
  1085. &imageBufferProcs, /*tp_as_buffer*/
  1086. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  1087. "DeckLink video source", /* tp_doc */
  1088. 0, /* tp_traverse */
  1089. 0, /* tp_clear */
  1090. 0, /* tp_richcompare */
  1091. 0, /* tp_weaklistoffset */
  1092. 0, /* tp_iter */
  1093. 0, /* tp_iternext */
  1094. videoMethods, /* tp_methods */
  1095. 0, /* tp_members */
  1096. videoGetSets, /* tp_getset */
  1097. 0, /* tp_base */
  1098. 0, /* tp_dict */
  1099. 0, /* tp_descr_get */
  1100. 0, /* tp_descr_set */
  1101. 0, /* tp_dictoffset */
  1102. (initproc)VideoDeckLink_init, /* tp_init */
  1103. 0, /* tp_alloc */
  1104. Image_allocNew, /* tp_new */
  1105. };
  1106. ////////////////////////////////////////////
  1107. // DeckLink Capture Delegate Class
  1108. ////////////////////////////////////////////
  1109. #endif // WITH_GAMEENGINE_DECKLINK