2013년 3월 28일 목요일

C++ double linked-list Template Queue

< BufferQueue.h - cpp 만들지 말것, 빌드시 링크에러 발생 >
 #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;
...
MediaBuffer *pBuffer = m_pVideoQue->pop_front();
...

* linked-list 로 할 수도 있지만 향후 확장성을 고려하여 double linked-list 로 구현

ffmpeg 로그 출력 설정



static void activex_av_log(const char *fmt, va_list vargs)
{
char szMsg[512] = {0};
vsprintf(szMsg, fmt, vargs);
OutputDebugString("[activex_av_log]");
OutputDebugString(szMsg);
}


static void av_log_output(void *ptr, int level, const char *fmt, va_list vargs)
{
KLog log;
static int print_prefix = 1;
AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
if (level > av_log_get_level())
return;
if (print_prefix && avc)
log.WriteFileLog("[%s @ %p]", avc->item_name(ptr), ptr);
print_prefix = strstr(fmt, "\n") != NULL;
activex_av_log(fmt, vargs);
//http_vlog(fmt, vargs);
}

...
int level = av_log_get_level();    // 로그레벨 가져오기
av_log_set_level(99);    // 로그레벨 설정
av_log_set_callback(av_log_output);   // 로그출력 콜백함수 설정


* 위와같이 설정하면 윈도우에서 debugview 를 통해 ffmpeg 로그를 볼수 있다

MinGW ffmpeg build configuration

./configure --enable-memalign-hack --extra-cflags="-fno-stack-check -fno-stack-protector -mno-stack-arg-probe"