be81f63d93c1f5af66d599fddc5c72eb9d8e41ed
[blender.git] / source / gameengine / VideoTexture / VideoDeckLink.h
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
28 /** \file VideoDeckLink.h
29  *  \ingroup bgevideotex
30  */
31
32 #ifndef __VIDEODECKLINK_H__
33 #define __VIDEODECKLINK_H__
34
35 #ifdef WITH_GAMEENGINE_DECKLINK
36
37 /* this needs to be parsed with __cplusplus defined before included through DeckLink_compat.h */
38 #if defined(__FreeBSD__)
39 #  include <inttypes.h>
40 #endif
41 #include <map>
42 #include <set>
43
44 extern "C" {
45 #include <pthread.h>
46 #include "DNA_listBase.h"
47 #include "BLI_threads.h"
48 #include "BLI_blenlib.h"
49 }
50 #include "GL/glew.h"
51 #ifdef WIN32
52 #include "dvpapi.h"
53 #endif
54 #include "DeckLinkAPI.h"
55 #include "VideoBase.h"
56
57 class PinnedMemoryAllocator;
58
59 struct TextureDesc
60 {
61         uint32_t        width;
62         uint32_t        height;
63         uint32_t        stride;
64         uint32_t        size;
65         GLenum          internalFormat;
66         GLenum          format;
67         GLenum          type;
68         TextureDesc()
69         {
70                 width = 0;
71                 height = 0;
72                 stride = 0;
73                 size = 0;
74                 internalFormat = 0;
75                 format = 0;
76                 type = 0;
77         }
78 };
79
80 class CaptureDelegate;
81
82 // type VideoDeckLink declaration
83 class VideoDeckLink : public VideoBase
84 {
85         friend class CaptureDelegate;
86 public:
87         /// constructor
88         VideoDeckLink (HRESULT * hRslt);
89         /// destructor
90         virtual ~VideoDeckLink ();
91
92         /// open video/image file
93         virtual void openFile(char *file);
94         /// open video capture device
95         virtual void openCam(char *driver, short camIdx);
96
97         /// release video source
98         virtual bool release (void);
99         /// overwrite base refresh to handle fixed image
100         virtual void refresh(void);
101         /// play video
102         virtual bool play (void);
103         /// pause video
104         virtual bool pause (void);
105         /// stop video
106         virtual bool stop (void);
107         /// set play range
108         virtual void setRange (double start, double stop);
109         /// set frame rate
110         virtual void setFrameRate (float rate);
111
112 protected:
113         // format and codec information
114         /// image calculation
115         virtual void calcImage (unsigned int texId, double ts);
116
117 private:
118         void                                    VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame);
119         void                                    LockCache()
120         {
121                 pthread_mutex_lock(&mCacheMutex);
122         }
123         void                                    UnlockCache()
124         {
125                 pthread_mutex_unlock(&mCacheMutex);
126         }
127
128         IDeckLinkInput*                 mDLInput;
129         BMDDisplayMode                  mDisplayMode;
130         BMDPixelFormat                  mPixelFormat;
131         bool                                    mUse3D;
132         uint32_t                                mFrameWidth;
133         uint32_t                                mFrameHeight;
134         TextureDesc                             mTextureDesc;
135         PinnedMemoryAllocator*  mpAllocator;
136         CaptureDelegate*                mpCaptureDelegate;
137
138         // cache frame in transit between the callback thread and the main BGE thread
139         // keep only one frame in cache because we just want to keep up with real time
140         pthread_mutex_t                 mCacheMutex;
141         IDeckLinkVideoInputFrame* mpCacheFrame;
142         bool                                    mClosing;
143
144 };
145
146 inline VideoDeckLink *getDeckLink(PyImage *self)
147 {
148         return static_cast<VideoDeckLink*>(self->m_image);
149 }
150
151 ////////////////////////////////////////////
152 // TextureTransfer : Abstract class to perform a transfer to GPU memory using fast transfer if available
153 ////////////////////////////////////////////
154 class TextureTransfer
155 {
156 public:
157         TextureTransfer() {}
158         virtual ~TextureTransfer() { }
159
160         virtual void PerformTransfer() = 0;
161 protected:
162         static bool _PinBuffer(void *address, uint32_t size);
163         static void _UnpinBuffer(void* address, uint32_t size);
164 };
165
166 ////////////////////////////////////////////
167 // PinnedMemoryAllocator
168 ////////////////////////////////////////////
169
170 // PinnedMemoryAllocator implements the IDeckLinkMemoryAllocator interface and can be used instead of the
171 // built-in frame allocator, by setting with SetVideoInputFrameMemoryAllocator() or SetVideoOutputFrameMemoryAllocator().
172 //
173 // For this sample application a custom frame memory allocator is used to ensure each address
174 // of frame memory is aligned on a 4kB boundary required by the OpenGL pinned memory extension.
175 // If the pinned memory extension is not available, this allocator will still be used and
176 // demonstrates how to cache frame allocations for efficiency.
177 //
178 // The frame cache delays the releasing of buffers until the cache fills up, thereby avoiding an
179 // allocate plus pin operation for every frame, followed by an unpin and deallocate on every frame.
180
181
182 class PinnedMemoryAllocator : public IDeckLinkMemoryAllocator
183 {
184 public:
185         PinnedMemoryAllocator(unsigned cacheSize, size_t memSize);
186         virtual ~PinnedMemoryAllocator();
187
188         void TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId);
189
190         // IUnknown methods
191         virtual HRESULT STDMETHODCALLTYPE       QueryInterface(REFIID iid, LPVOID *ppv);
192         virtual ULONG STDMETHODCALLTYPE         AddRef(void);
193         virtual ULONG STDMETHODCALLTYPE         Release(void);
194
195         // IDeckLinkMemoryAllocator methods
196         virtual HRESULT STDMETHODCALLTYPE       AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer);
197         virtual HRESULT STDMETHODCALLTYPE       ReleaseBuffer(void* buffer);
198         virtual HRESULT STDMETHODCALLTYPE       Commit();
199         virtual HRESULT STDMETHODCALLTYPE       Decommit();
200
201 private:
202         static bool                             mGPUDirectInitialized;
203         static bool                             mHasDvp;
204         static bool                             mHasAMDPinnedMemory;
205         static size_t                   mReservedProcessMemory;
206         static bool ReserveMemory(size_t size);
207
208         void Lock()
209         {
210                 pthread_mutex_lock(&mMutex);
211         }
212         void Unlock()
213         {
214                 pthread_mutex_unlock(&mMutex);
215         }
216         HRESULT _ReleaseBuffer(void* buffer);
217
218         uint32_t                                                        mRefCount;
219         // protect the cache and the allocated map, 
220         // not the pinnedBuffer map as it is only used from main thread
221         pthread_mutex_t                                         mMutex;
222         std::map<void*, uint32_t>                       mAllocatedSize;
223         std::vector<void*>                                      mBufferCache;
224         std::map<void *, TextureTransfer*>      mPinnedBuffer;
225 #ifdef WIN32
226         DVPBufferHandle                                         mDvpCaptureTextureHandle;
227 #endif
228         // target texture in GPU
229         GLuint                                                          mTexId;
230         uint32_t                                                        mBufferCacheSize;
231 };
232
233 ////////////////////////////////////////////
234 // Capture Delegate Class
235 ////////////////////////////////////////////
236
237 class CaptureDelegate : public IDeckLinkInputCallback
238 {
239         VideoDeckLink*  mpOwner;
240
241 public:
242         CaptureDelegate(VideoDeckLink* pOwner);
243
244         // IUnknown needs only a dummy implementation
245         virtual HRESULT STDMETHODCALLTYPE       QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
246         virtual ULONG   STDMETHODCALLTYPE       AddRef()                                                                { return 1; }
247         virtual ULONG   STDMETHODCALLTYPE       Release()                                                               { return 1; }
248
249         virtual HRESULT STDMETHODCALLTYPE       VideoInputFrameArrived(IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioPacket);
250         virtual HRESULT STDMETHODCALLTYPE       VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags);
251 };
252
253
254 #endif  /* WITH_GAMEENGINE_DECKLINK */
255
256 #endif  /* __VIDEODECKLINK_H__ */