音視頻同步系列文章之—-一種基於RTP協議的用戶端媒體流Buffer管理思想(2)

來源:互聯網
上載者:User

三、緩衝區的動態分配與實現。

    基於這樣的一個事實,音頻資料遠遠小於視頻資料。所以在這裡把音頻緩衝區與視頻緩衝區分開管理。並且根據統計,同一媒體流的RTP資料包大小相近,比如,音頻大概幾百個Byte,視頻1.3kByte。對視頻緩衝區,我們分為兩部分。一部分為正在使用資料區,一部分為空白閑區。當RTP接收到資料後,就從空閑區取得一個Memory塊。這個塊的大小大於或等於接收到的資料與Packet頭部之和。取得Memory塊後,將資料拷貝進來,然後根據幀序號和包序號,插入到正在使用資料區,供播放器調用。播放器在正在使用資料區取得一幀資料,解碼,播放。使用完後該資料區塊並不立即釋放,而是有序的插入到空閑資料區。

    這樣的Memory重複利用思想要用到上節中介紹的指標數組和指標隊列。指標資料用來管理空閑資料區塊鏈。實現按大小有序插入和尋找。指標隊列用來管理排序之後的資料幀,按幀序號和包序號排放。我們這裡將一個視訊框架分成若干個RTP包。

    首先,定義CMyPtrArray  m_FreeList,用來管理空閑資料有序鏈。

    在空閑區申請Memory塊的方法如下:

ppFrameBuf 為返回資料區塊指標,FRAME_BUFFER是一個虛擬結構,包括Buffer實際長度和指向Buffer的指標和其他自訂成員,nLen為申請大小。

 

void GetOneFreeBuf(FRAME_BUFFER **ppFrameBuf,DWORD nLen)
{
 if(NULL == ppFrameBuf)
  return ;
 FRAME_BUFFER *pFrameBuf = NULL;
 //此處添加互斥代碼
 if(m_FreeList.GetSize() > 0)
 {
  int nStart = 0,nEnd = m_FreeList.GetSize();
  int nCur = (nStart + nEnd) / 2;
  FRAME_BUFFER *pTmpBuf = NULL;
  while(1)
  {
   pTmpBuf = (FRAME_BUFFER *)m_FreeList.GetAt(nCur);
   if((pTmpBuf->nBufSize >= nLen) && ((pTmpBuf->nBufSize - nLen) <= 100))
    break;
   else if(pTmpBuf->nBufSize > nLen)
    nEnd = nCur;
   else
    nStart = nCur;
   nCur = (nStart + nEnd) / 2;
   if(nCur == nStart || nCur == nEnd)
   {
    pTmpBuf = (FRAME_BUFFER *)m_FreeList.GetAt(nCur);
    break;
   }
  }
  if(nCur >= m_FreeList.GetSize())
   nCur = m_FreeList.GetSize() -1;
  if(pTmpBuf->nBufSize < nLen && nCur < (m_FreeList.GetSize() - 1))
  {
   nCur ++;
   pTmpBuf = (FRAME_BUFFER *)m_FreeList.GetAt(nCur);
  }
  if(pTmpBuf->nBufSize >= nLen)
  {
   pFrameBuf = pTmpBuf;
  // 
   m_FreeList.RemoveAt(nCur);
  }
 }
 *ppFrameBuf = NULL;
 if(NULL == pFrameBuf)
 {
  pFrameBuf = new FRAME_BUFFER;
  if(NULL == pFrameBuf)
  {
   return;
  }
  pFrameBuf->nBufSize = nLen;
  pFrameBuf->pFrameData = new BYTE[nLen + 100];
  if(NULL == pFrameBuf->pFrameData)
  {
   delete pFrameBuf;
   return ;
  }
 }
//  TRACE("CStreamBuffer::GetOneFreeBuf,NeedSize:%d,ActualSize:%d/n",nLen,pFrameBuf->nBufSize);
 *ppFrameBuf = pFrameBuf;
}

 

釋放Memory塊到空閑去的方法如下:

void ReleaseBuf(FRAME_BUFFER *pFrameBuf)//從小到大排序
{
 if(NULL == pFrameBuf || NULL == pFrameBuf->pFrameData || 0 == pFrameBuf->nBufSize)
  return ;
 FRAME_BUFFER *pTmpBuf = NULL;
 //添加互斥代碼
 DWORD nCur = 0;
 if(m_FreeList.GetSize() > 0)
 {
  DWORD nStart = 0,nEnd = m_FreeList.GetSize();
  nCur = (nStart + nEnd) / 2;
  while(1)
  {
   pTmpBuf = (FRAME_BUFFER *)m_FreeList.GetAt(nCur);
   if(pTmpBuf->nBufSize == pFrameBuf->nBufSize)
    break;
   else if(pTmpBuf->nBufSize > pFrameBuf->nBufSize)
    nEnd = nCur;
   else
    nStart = nCur;
   nCur = (nStart + nEnd) / 2;
   if(nCur == nStart || nCur == nEnd)
    break;
  }
  if(nCur > 0 && pTmpBuf->nBufSize > pFrameBuf->nBufSize)
   nCur --;
 }

 m_FreeList.InsertAt(nCur,pFrameBuf);
}

 

 

當然程式退出時,要記得釋放所有申請的空間。

四、緩衝區設計

    有了前面的技術基礎。我們就可以從容的設計自己的緩衝區了。因為音頻資料比視頻資料小一個數量級。所以,可以將一個音訊框架打包為一個RTP包。而將一個視訊框架打包為多個RTP包。對應的,在用戶端。我們收到一個RTP音頻包可以直接送入音訊框架隊列,供播放器使用。收到RTP視頻包,首先要組成完整幀,然後供播放器使用。緩衝區如下:

                                                                            

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.