AJA NTV2 SDK  17.1.1.1245
NTV2 SDK 17.1.1.1245
circularbuffer.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #ifndef AJA_CIRCULAR_BUFFER_H
9 #define AJA_CIRCULAR_BUFFER_H
10 
11 #include "ajabase/common/public.h"
12 #include "ajabase/system/lock.h"
13 #include "ajabase/system/event.h"
14 
15 
16 
29 template <typename FrameDataPtr>
31 {
32 public:
37 
38 
42  virtual ~AJACircularBuffer ();
43 
44 
51  inline void SetAbortFlag (const bool * pAbortFlag)
52  {
53  mAbortFlag = pAbortFlag;
54  }
55 
56 
61  inline unsigned int GetCircBufferCount (void) const
62  {
63  return mCircBufferCount;
64  }
65 
66 
71  inline bool IsEmpty (void) const
72  {
73  return GetCircBufferCount () == 0;
74  }
75 
80  inline unsigned int GetNumFrames (void) const
81  {
82  return (unsigned int) mFrames.size ();
83  }
84 
85 
92  AJAStatus Add (FrameDataPtr pInFrameData)
93  {
94  mFrames.push_back(pInFrameData);
95  AJALock* lock = new AJALock;
96  mLocks.push_back(lock);
97 
98  return (mFrames.size() == mLocks.size() && lock) ? AJA_STATUS_SUCCESS
100  }
101 
102 
109  FrameDataPtr StartProduceNextBuffer (void)
110  {
111  while (1)
112  {
113  if( !WaitForLockOrAbort(&mDataBufferLock) )
114  return NULL;
115 
116  if ( mCircBufferCount == mFrames.size() )
117  {
118  mDataBufferLock.Unlock();
119  if( !WaitForEventOrAbort(&mNotFullEvent) )
120  return NULL;
121 
122  continue;
123  }
124  break;
125  }
126  if( !WaitForLockOrAbort(mLocks[mHead]) ) return NULL;
127  mFillIndex = mHead;
128  mHead = (mHead+1)%((unsigned int)(mFrames.size()));
129  mCircBufferCount++;
130  if( mCircBufferCount == mFrames.size() )
131  mNotFullEvent.SetState(false);
132 
133  mDataBufferLock.Unlock();
134 
135  return mFrames[mFillIndex];
136  }
137 
138 
144  void EndProduceNextBuffer (void);
145 
146 
153  FrameDataPtr StartConsumeNextBuffer (void)
154  {
155  while (1)
156  {
157  if( !WaitForLockOrAbort(&mDataBufferLock) )
158  return NULL;
159 
160  if ( mCircBufferCount == 0 )
161  {
162  mDataBufferLock.Unlock();
163  if( !WaitForEventOrAbort(&mNotEmptyEvent) )
164  return NULL;
165 
166  continue;
167  }
168  break;
169  }
170 
171  if( !WaitForLockOrAbort(mLocks[mTail]) )
172  return NULL;
173 
174  mEmptyIndex = mTail;
175  mTail = (mTail+1)%((unsigned int)mFrames.size());
176  mCircBufferCount--;
177  if( mCircBufferCount == 0 )
178  mNotEmptyEvent.SetState(false);
179  mDataBufferLock.Unlock();
180 
181  return mFrames[mEmptyIndex];
182  }
183 
184 
190  void EndConsumeNextBuffer (void);
191 
192 
198  void Clear (void);
199 
200 
201 private:
202  typedef std::vector <AJALock *> AJALockVector;
203 
204  std::vector <FrameDataPtr> mFrames;
205  AJALockVector mLocks;
206 
207  unsigned int mHead;
208  unsigned int mTail;
209  unsigned int mCircBufferCount;
210  AJAEvent mNotFullEvent;
211  AJAEvent mNotEmptyEvent;
212  AJALock mDataBufferLock;
213 
214  unsigned int mFillIndex;
215  unsigned int mEmptyIndex;
216 
217  const bool * mAbortFlag;
218 
224  bool WaitForEventOrAbort (AJAEvent * ajaEvent);
225 
226 
232  bool WaitForLockOrAbort (AJALock * ajaEvent);
233 
234 }; // AJACircularBuffer
235 
236 
237 
238 template <typename FrameDataPtr>
240  : mHead (0),
241  mTail (0),
242  mCircBufferCount (0),
243  mFillIndex (0),
244  mEmptyIndex (0),
245  mAbortFlag (NULL)
246 {
247 }
248 
249 template <typename FrameDataPtr>
250 AJACircularBuffer <FrameDataPtr>::~AJACircularBuffer ()
251 {
252  Clear ();
253 }
254 
255 
256 
257 
258 template<typename FrameDataPtr>
260 {
261  mLocks[mFillIndex]->Unlock();
262  mNotEmptyEvent.SetState(true);
263 }
264 
265 template<typename FrameDataPtr>
267 {
268  mLocks[mEmptyIndex]->Unlock();
269  mNotFullEvent.SetState(true);
270 }
271 
272 template<typename FrameDataPtr>
274 {
275  const unsigned int timeout = 100;
276 
277  do {
278  AJAStatus status = ajaEvent->WaitForSignal(timeout);
279  if (status == AJA_STATUS_TIMEOUT)
280  if ( mAbortFlag )
281  if ( *mAbortFlag )
282  return false;
283  if (status == AJA_STATUS_FAIL)
284  return false;
285  if (status == AJA_STATUS_SUCCESS )
286  break;
287  } while(1);
288 
289  return true;
290 }
291 
292 template<typename FrameDataPtr>
294 {
295  const unsigned int timeout = 100;
296 
297  do {
298  AJAStatus status = ajaLock->Lock(timeout);
299  if (status == AJA_STATUS_TIMEOUT)
300  if ( mAbortFlag )
301  if ( *mAbortFlag)
302  return false;
303  if (status == AJA_STATUS_FAIL)
304  return false;
305  if (status == AJA_STATUS_SUCCESS )
306  break;
307  } while(1);
308 
309  return true;
310 }
311 
312 
313 template<typename FrameDataPtr>
315 {
316  for (AJALockVector::iterator iter (mLocks.begin()); iter != mLocks.end(); ++iter)
317  delete *iter;
318 
319  mLocks.clear();
320  mFrames.clear();
321 
322  mHead = mTail = mFillIndex = mEmptyIndex = mCircBufferCount = 0;
323  mAbortFlag = NULL;
324 }
325 
326 
327 #endif // AJA_CIRCULAR_BUFFER_H
NULL
#define NULL
Definition: ntv2caption608types.h:19
AJA_STATUS_SUCCESS
@ AJA_STATUS_SUCCESS
Definition: types.h:381
AJACircularBuffer::AJACircularBuffer
AJACircularBuffer()
My default constructor.
Definition: circularbuffer.h:239
AJACircularBuffer::StartConsumeNextBuffer
FrameDataPtr StartConsumeNextBuffer(void)
The thread that's responsible for processing incoming frames – the consumer – calls this function to ...
Definition: circularbuffer.h:153
AJACircularBuffer::EndProduceNextBuffer
void EndProduceNextBuffer(void)
The producer thread calls this function to signal that it has finished populating the frame it obtain...
Definition: circularbuffer.h:259
AJAEvent::WaitForSignal
virtual AJAStatus WaitForSignal(uint32_t timeout=0xffffffff)
Definition: event.cpp:87
public.h
Master header for the ajabase library.
AJAStatus
AJAStatus
Definition: types.h:378
AJACircularBuffer::GetCircBufferCount
unsigned int GetCircBufferCount(void) const
Retrieves the size count of the circular buffer, i.e. how far the tail pointer is behind the head poi...
Definition: circularbuffer.h:61
AJACircularBuffer::Add
AJAStatus Add(FrameDataPtr pInFrameData)
Appends a new frame buffer to me, increasing my frame storage capacity by one frame.
Definition: circularbuffer.h:92
lock.h
Declares the AJALock class.
AJA_STATUS_FAIL
@ AJA_STATUS_FAIL
Definition: types.h:382
AJAEvent::SetState
virtual AJAStatus SetState(bool signaled=true)
Definition: event.cpp:59
AJAEvent
Definition: event.h:21
AJACircularBuffer::StartProduceNextBuffer
FrameDataPtr StartProduceNextBuffer(void)
The thread that's responsible for providing frames – the producer – calls this function to populate t...
Definition: circularbuffer.h:109
AJACircularBuffer::IsEmpty
bool IsEmpty(void) const
Returns "true" if I'm empty – i.e., if my tail and head are in the same place.
Definition: circularbuffer.h:71
event.h
Declares the AJAEvent class.
AJACircularBuffer::EndConsumeNextBuffer
void EndConsumeNextBuffer(void)
The consumer thread calls this function to signal that it has finished processing the frame it obtain...
Definition: circularbuffer.h:266
AJACircularBuffer::GetNumFrames
unsigned int GetNumFrames(void) const
Returns my frame storage capacity, which reflects how many times my Add method has been called.
Definition: circularbuffer.h:80
AJALock::Lock
virtual AJAStatus Lock(uint32_t timeout=0xffffffff)
Definition: lock.cpp:69
AJALock
Definition: lock.h:30
AJA_STATUS_TIMEOUT
@ AJA_STATUS_TIMEOUT
Definition: types.h:384
AJACircularBuffer::Clear
void Clear(void)
Clears my frame collection, their locks, everything.
Definition: circularbuffer.h:314
AJACircularBuffer::~AJACircularBuffer
virtual ~AJACircularBuffer()
My destructor.
Definition: circularbuffer.h:250
AJACircularBuffer::SetAbortFlag
void SetAbortFlag(const bool *pAbortFlag)
Tells me the boolean variable I should monitor such that when it gets set to "true" will cause any th...
Definition: circularbuffer.h:51
AJALock::Unlock
virtual AJAStatus Unlock()
Definition: lock.cpp:89
AJACircularBuffer
I am a circular frame buffer that simplifies implementing a type-safe producer/consumer model for pro...
Definition: circularbuffer.h:30