#ifndef __BUFFER_QUEUE_H__
#define __BUFFER_QUEUE_H__
#include "Mutex.h"
#include "CommonType.h"
template <typename T>
class BufferQueue
{
public:
BufferQueue(int maxQueCount);
virtual ~BufferQueue();
int push_back(T *data);
T* pop_front();
int push_front(T *data);
T* pop_back();
void clear();
int count() { return m_nCount; }
int maxCount() { return m_nMaxQueCount; }
bool isFull();
protected:
int m_nMaxQueCount;
int m_nCount;
MUTEX m_hMutex;
template <typename DT>
class Element
{
friend class BufferQueue<DT>;
private:
Element(DT *inData) : data(inData), next(NULL), prev(NULL)
{}
DT *data;
Element *next, *prev;
};
Element<T> *m_pHead, *m_pTail;
};
// 템플릿은 미리 컴파일이 되어있어야 함
template <typename T>
BufferQueue<T>::BufferQueue(int maxQueCount)
{
m_nMaxQueCount = maxQueCount;
m_nCount = 0;
m_pHead = m_pTail = NULL;
MUTEX_INIT(&m_hMutex);
}
template <typename T>
BufferQueue<T>::~BufferQueue()
{
clear();
MUTEX_DESTROY(&m_hMutex);
}
template <typename T>
void BufferQueue<T>::clear()
{
MUTEX_LOCK(&m_hMutex);
Element<T> *tmp;
T *data;
while (m_pHead != NULL)
{
tmp = m_pHead;
m_pHead = tmp->next;
data = tmp->data;
delete data;
delete tmp;
}
m_pHead = m_pTail = NULL;
m_nCount = 0;
MUTEX_UNLOCK(&m_hMutex);
}
template <typename T>
int BufferQueue<T>::push_back(T *data)
{
MUTEX_LOCK(&m_hMutex);
if (m_nMaxQueCount > 0) {
if (m_nCount >= m_nMaxQueCount) {
MUTEX_UNLOCK(&m_hMutex);
return -1;
}
}
Element<T> *elm = new Element<T>(data);
if (m_pHead == NULL)
{
m_pHead = elm;
m_pTail = elm;
}
else
{
elm->prev = m_pTail;
m_pTail->next = elm;
m_pTail = elm;
}
m_nCount++;
MUTEX_UNLOCK(&m_hMutex);
return m_nCount;
}
template <typename T>
T* BufferQueue<T>::pop_front()
{
MUTEX_LOCK(&m_hMutex);
Element<T> *elm;
T *data = NULL;
if (m_nCount == 0)
goto exit;
if (m_pHead == NULL)
goto exit;
elm = m_pHead;
data = m_pHead->data;
m_pHead = m_pHead->next;
if (m_pHead) m_pHead->prev = NULL;
delete elm;
if (!m_pHead)
m_pTail = NULL;
m_nCount--;
exit:
MUTEX_UNLOCK(&m_hMutex);
return data;
}
template <typename T>
int BufferQueue<T>::push_front(T *data)
{
MUTEX_LOCK(&m_hMutex);
if (m_nMaxQueCount > 0) {
if (m_nCount >= m_nMaxQueCount) {
MUTEX_UNLOCK(&m_hMutex);
return -1;
}
}
Element<T> *elm = new Element<T>(data);
if (m_pHead == NULL)
{
m_pHead = elm;
m_pTail = elm;
}
else
{
elm->next = m_pHead;
m_pHead->prev = elm;
m_pHead = elm;
}
m_nCount++;
MUTEX_UNLOCK(&m_hMutex);
return m_nCount;
}
template <typename T>
T* BufferQueue<T>::pop_back()
{
MUTEX_LOCK(&m_hMutex);
Element<T> *elm;
T *data = NULL;
if (m_nCount == 0)
goto exit;
if (m_pTail == NULL)
goto exit;
elm = m_pTail;
data = m_pTail->data;
m_pTail = m_pTail->prev;
if (m_pTail) m_pTail->next = NULL;
delete elm;
if (!m_pTail)
m_pHead = NULL;
m_nCount--;
exit:
MUTEX_UNLOCK(&m_hMutex);
return data;
}
template <typename T>
bool BufferQueue<T>::isFull()
{
if (m_nMaxQueCount > 0) {
return m_nCount>=m_nMaxQueCount;
}
return false;
}
#endif
< BufferQueue 사용 >
class MediaBuffer
{
public:
enum MediaType mediaType;
char *data;
int size;
int streamIndex;
int keyFrame;
__int64 timestamp;
__int64 pos;
}
...
BufferQueue<MediaBuffer> *m_pVideoQue = new BufferQueue<MediaBuffer>(30);
...
MediaBuffer *pBuffer = new MediaBuffer();
if (m_pVideoQue->push_back(pBuffer) < 0)
delete pBuffer;
delete pBuffer;
...
MediaBuffer *pBuffer = m_pVideoQue->pop_front();
...
* linked-list 로 할 수도 있지만 향후 확장성을 고려하여 double linked-list 로 구현