NifTK  16.4.1 - 0798f20
CMIC's Translational Medical Imaging Platform
niftkNVidiaSDIDataSourceImpl.h
Go to the documentation of this file.
1 /*=============================================================================
2 
3  NifTK: A software platform for medical image computing.
4 
5  Copyright (c) University College London (UCL). All rights reserved.
6 
7  This software is distributed WITHOUT ANY WARRANTY; without even
8  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9  PURPOSE.
10 
11  See LICENSE.txt in the top level directory for details.
12 
13 =============================================================================*/
14 
15 #ifndef niftkNVidiaSDIDataSourceImpl_h
16 #define niftkNVidiaSDIDataSourceImpl_h
17 
18 #include <QThread>
19 #include <QMutex>
20 #include <QWaitCondition>
21 #include <QGLWidget>
22 #include <cuda.h>
23 #include <video/sdiinput.h>
24 #include <video/compress.h>
25 #include <video/decompress.h>
26 #include <opencv2/core/types_c.h>
27 #include <string>
29 
30 namespace niftk
31 {
32 
33 // after construction, call start() to kick off capture
34 // beware: all signal/event processing for this object needs to happen on this thread!
35 // so if you didnt call start(), trying to emit Bump will mess up.
37 {
38  Q_OBJECT
39 
40 public:
41 
43  {
46  FAILED, // something is broken. as of recently, signal drop out is considered failed!
47  RUNNING, // trying to capture
48  DEAD, // e.g. no suitable hardware in the system
50  };
51 
52 
53 public:
56 
57  int GetTextureId(unsigned int stream) const;
58  QGLWidget* GetCaptureContext();
59 
62 
64  std::pair<int, int> GetCaptureFormat() const;
65  int GetStreamCount() const;
66  // FIXME: should have a getter for the above two to avoid excessive locking
67 
70  void Reset();
71 
74 
81  int GetRGBAImage(unsigned int sequencenumber, IplImage* targetbuffer);
82 
83  // returns the next sequence number that has already been captured
84  // following ihavealready.
85  // returns zero if no new ones have arrived yet.
86  video::FrameInfo GetNextSequenceNumber(unsigned int ihavealready) const;
87 
88  const char* GetWireFormatString() const;
89 
90  unsigned int GetCookie() const;
91 
92  bool IsRunning() const;
93 
96 
97  // instead of emitting the compress signal directly you should call this function
98  unsigned int CompressFrame(unsigned int sequencenumber);
99  void StopCompression();
100 
104  void TryPlayback(const std::string& filename);
105  // stops realtime capture if on=true and enables decompressor.
106  // use GetRGBAImage() to retrieve a frame.
107  void SetPlayback(bool on, int expectedstreamcount = 0);
108 
109 protected:
110 
111  // repeatedly called by timer to check for new frames.
112  virtual void OnTimeoutImpl();
113 
114  bool HasHardware() const;
115  bool HasInput() const;
116 
117  // qt thread
118  virtual void run();
119 
120  bool DumpNALIndex() const;
121 
122 protected slots:
123 
124  void DoWakeUp();
125 
126  // can only be used with Qt::BlockingQueuedConnection!
127  void DoCompressFrame(unsigned int sequencenumber, unsigned int* frameindex);
128  void DoStopCompression();
129  void DoGetRGBAImage(unsigned int sequencenumber, IplImage** img, unsigned int* streamcount);
130  void DoTryPlayback(const char* filename, bool* ok, const char** errormsg);
131 
132 signals:
133 
134  // bumping this thread means to wake it up from its timer sleep.
135  // this is a queued connection.
136  void SignalBump();
137 
138  // these are blocking queued connections!
139  void SignalCompress(unsigned int sequencenumber, unsigned int* frameindex);
140  void SignalStopCompression();
141  void SignalGetRGBAImage(unsigned int sequencenumber, IplImage** img, unsigned int* streamcount);
142  void SignalTryPlayback(const char* filename, bool* ok, const char** errormsg);
143 
144  // emitted when capture setup dies. should be connected with a non-blocking queued connection!
145  void SignalFatalError(QString msg);
146 
147 private:
148  // has to be called with lock held!
149  void InitVideo();
150 
158  void ReadbackRGBA(char* buffer, std::size_t bufferpitch, int width, int height, int slot);
159 
163  void ReadbackViaPBO(char* buffer, std::size_t bufferpitch, int width, int height, int slot);
164 
165  void DecompressRGBA(unsigned int sequencenumber, IplImage** img, unsigned int* streamcountinimg);
166 
167  // any access to members needs to be locked
168  mutable QMutex lock;
169 
170  // all the sdi stuff needs an opengl context
171  // so we'll create our own
172  QGLWidget* oglwin;
173  // we want to share our capture context with other render contexts (e.g. the preview widget)
174  // but for that to work we need a hack because for sharing to work, the share-source cannot
175  // be current at the time of call. but our capture context is current (to the capture thread)
176  // all the time! so we just create a dummy context that shares with capture-context but itself
177  // is never ever current to any thread and hence can be shared with new widgets while capture-context
178  // is happily working away. and tada it works :)
179  QGLWidget* oglshare;
180 
181  CUcontext cuContext;
182 
183  CaptureState current_state;
184  std::string state_message;
185 
186  video::SDIDevice* sdidev;
187  video::SDIInput* sdiin;
189  int streamcount;
190  const char* wireformat;
191 
192  // cached capture image dimensions, so that getters can be called from any thread.
193  int m_CaptureWidth;
194  int m_CaptureHeight;
195 
196  // we keep our own copy of the texture ids (instead of relying on sdiin)
197  // so that another thread can easily get these.
198  // SDIInput is actively enforcing an opengl context check that's incompatible
199  // with the current threading situation.
200  int textureids[4];
201 
202  video::Compressor* compressor;
203 
204  struct SequenceNumberComparator
205  {
206  bool operator()(const video::FrameInfo& a, const video::FrameInfo& b) const;
207  };
208 
209  // maps sequence numbers to ringbuffer slots
210  std::map<video::FrameInfo, int, SequenceNumberComparator> sn2slot_map;
211  // maps ringbuffer slots to sequence numbers
212  std::map<int, video::FrameInfo> slot2sn_map;
213 
214  video::Decompressor* decompressor;
215 
216  // time stamp of the previous successfully captured frame.
217  // this is used to detect a capture glitch without unconditionally blocking for new frames.
218  // see QmitkIGINVidiaDataSourceImpl::OnTimeoutImpl().
219  DWORD m_LastSuccessfulFrame;
220 
221  // used in a log file to correlate times stamps, frame index and sequence number
222  unsigned int m_NumFramesCompressed;
223 
225 
226  // used to check whether any in-flight IGINVidiaDataType are still valid.
227  // it is set during InitVideo().
228  unsigned int m_Cookie;
229 
230  std::string m_CompressionOutputFilename;
231 
232  // pixel buffer objects used for async readback of the video frames.
233  // some perf testing and profiling revealed that we spend a lot of time in the driver
234  // for synchronously reading a texture image.
235  std::vector<int> m_ReadbackPBOs;
236 };
237 
238 } // end namespace
239 
240 #endif
void SetPlayback(bool on, int expectedstreamcount=0)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:1082
void DoStopCompression()
Definition: niftkNVidiaSDIDataSourceImpl.cxx:1059
Definition: compress.h:78
bool DumpNALIndex() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:1143
Definition: frame.h:26
Definition: sdiinput.h:31
virtual void OnTimeoutImpl()
Derived classes implement this.
Definition: niftkNVidiaSDIDataSourceImpl.cxx:620
Definition: niftkNVidiaSDIDataSourceImpl.h:46
Definition: device.h:30
video::StreamFormat GetFormat() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:459
video::FrameInfo GetNextSequenceNumber(unsigned int ihavealready) const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:438
Definition: frame.h:69
void TryPlayback(const std::string &filename)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:1253
InterlacedBehaviour
Definition: sdiinput.h:42
void SetFieldMode(video::SDIInput::InterlacedBehaviour mode)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:504
GLenum mode
Definition: glew.h:2404
Definition: decompress.h:47
GLdouble GLdouble GLdouble b
Definition: glew.h:7885
void DoGetRGBAImage(unsigned int sequencenumber, IplImage **img, unsigned int *streamcount)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:885
GLuint GLuint stream
Definition: glew.h:6079
std::string GetStateMessage() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:528
std::pair< int, int > GetCaptureFormat() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:476
void Reset()
Definition: niftkNVidiaSDIDataSourceImpl.cxx:810
Definition: niftkNVidiaSDIDataSourceImpl.h:49
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:8272
void SignalFatalError(QString msg)
void DoCompressFrame(unsigned int sequencenumber, unsigned int *frameindex)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:953
void SignalTryPlayback(const char *filename, bool *ok, const char **errormsg)
bool HasInput() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:414
~NVidiaSDIDataSourceImpl()
Definition: niftkNVidiaSDIDataSourceImpl.cxx:149
GLuint buffer
Definition: glew.h:1664
void SignalCompress(unsigned int sequencenumber, unsigned int *frameindex)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: glew.h:1238
Definition: niftkNVidiaSDIDataSourceImpl.h:44
NVidiaSDIDataSourceImpl()
Definition: niftkNVidiaSDIDataSourceImpl.cxx:73
void StopCompression()
Definition: niftkNVidiaSDIDataSourceImpl.cxx:1075
CaptureState
Definition: niftkNVidiaSDIDataSourceImpl.h:42
bool IsRunning() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:398
CaptureState GetCaptureState() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:520
Definition: niftkNVidiaSDIDataSourceImpl.h:47
GLint GLint GLint GLint GLint GLint GLsizei GLsizei height
Definition: glew.h:1236
GLuint const GLchar * name
Definition: glew.h:1798
std::string GetCompressionOutputFilename() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:536
virtual void run()
Override the QThread run method to start the thread.
Definition: niftkNVidiaSDIDataSourceImpl.cxx:552
void DoWakeUp()
Definition: niftkNVidiaSDIDataSourceImpl.cxx:613
video::SDIInput::InterlacedBehaviour GetFieldMode() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:512
int GetStreamCount() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:496
GLint GLvoid * img
Definition: glew.h:1369
int GetTextureId(unsigned int stream) const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:484
Definition: niftkNVidiaSDIDataSourceImpl.h:48
void SignalGetRGBAImage(unsigned int sequencenumber, IplImage **img, unsigned int *streamcount)
unsigned int CompressFrame(unsigned int sequencenumber)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:1050
Definition: niftkNVidiaSDIDataSourceImpl.h:36
GLint GLint GLint GLint GLint GLint GLsizei width
Definition: glew.h:1236
QGLWidget * GetCaptureContext()
Definition: niftkNVidiaSDIDataSourceImpl.cxx:467
const char * GetWireFormatString() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:430
int GetRGBAImage(unsigned int sequencenumber, IplImage *targetbuffer)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:941
void DoTryPlayback(const char *filename, bool *ok, const char **errormsg)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:1176
unsigned int GetCookie() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:422
Base class for threads that are simply triggered off of a QTimer.
Definition: niftkIGITimerBasedThread.h:32
Definition: niftkExceptionObject.h:21
bool HasHardware() const
Definition: niftkNVidiaSDIDataSourceImpl.cxx:406
GLsizei const GLcharARB ** string
Definition: glew.h:5194
void setCompressionOutputFilename(const std::string &name)
Definition: niftkNVidiaSDIDataSourceImpl.cxx:544
Definition: niftkNVidiaSDIDataSourceImpl.h:45