視頻監控客戶端開發(IP Camera)總結

做了將近三年時間的視頻監控客戶端開發,當然期間也做個一些其他開發。在開發期間,經對系統不斷進行重構優化積累了一些經驗,現向大家分享一下。希望以此拋磚引玉,有這方面經驗的朋友也發表一下看法和見解:

首先看下項目需求:
  1.最多同時支持16路高清音視頻同時顯示。
  2.窗口模式,全屏,1窗口,4窗口,9窗口,16窗口。
  3.播放控制,開始播放,停止播放,開啓音頻,停止音頻,雲臺控制,Camera管理。

 下面談談設計方案:

 1.總體設計,按照碼流數據流向,可以將系統分成三層:

  網絡層,負責碼流的接收,數據的解包,以及網絡故障的處理。
  解碼顯示層,網絡層將數據解包後提交給解碼層,解碼層負責碼流解碼和圖像顯示。
  UI層,負責響應消息並進行處理。

  處理原則:層與層之間儘量獨立,比如網絡層發現網絡故障後,進行以下處理:

  1.通知UI網絡故障。
  2.自行進行網絡重連。
  3.故障恢復後通往UI層網絡故障恢復。

  期間並不需要通知解碼顯示層暫停解碼顯示。解碼顯示層收不到網絡層提交的碼流,自然會暫停解碼

 1.線程模型

  先前的時候我的實現方式是,針對每一個播放窗口開一個線程,在這個線程中進行碼流接收,然後進行解碼顯示。後來發現有諸多問題,其中最嚴重的就是解碼耗時過長導致發送端經常出現發送超時的情形。

  現在的實現方式是針對以上各層實現三類線程:
  
  網絡數據接收線程:負責網絡數據接收,網絡連接建立。由於最大隻有16路碼流數據,使用select進行多路複用足夠滿足我的需求。網絡層還負責對碼流數據進行解包和校驗,測試證明進行數據解包和校驗並不影響網絡層的數據接收實時性。

  解碼顯示線程:負責數據的解碼和顯示,開始我分別使用Semaphore和Event進行線程同步,這樣造成了諸多不便,比如程序退出時需要SetEvent喚醒解碼線程,暫停和開始播放也需要進行特殊處理,後來我採用最簡潔明瞭的方式:用一個Sleep(1)解決了諸多同步上的問題。
while(!bExit)
{
if(bPlay)
{
 if(有數據)
解碼顯示一幀數據;
 else 
Sleep(1);
}
}
   UI線程,主要負責消息響應,UI線程在任何時候都不能阻塞,比如登陸操作直接提交給網絡層,網絡層收到登陸響應後再通知UI。

    2.數據模型

     網絡層收到數據經解碼後得到一幀一幀數據,由於每幀數據長度非常大(I幀比P幀長的多),定義一個固定長度的緩衝區存放一幀數據不是很好的做法。使用鏈表則會不斷的分配和釋放內存,造成內存碎片。使用循環緩衝區會增加一次數據拷貝。爲此我對循環緩衝區進行擴展:
   
   每次寫入一幀數據,寫入一幀數據之前先寫入該幀數據的長度。
   如果到了緩衝區的末尾,無法容納一幀完整的數據,直接跳到緩衝區的開始位置寫入數據。當然需要進行一些特殊處理。

   3.其他方面:
   使用Directshow框架可以方便解碼顯示,Directshow採用DirectDraw進行圖像顯示,效率有明顯的提升。
   Directshow的窗口模式比無窗口模式要容易控制,比如針對某個窗口進行顯示和隱藏。
   全屏播放的最好方法是:先將窗口最大化,置頂,然後隱藏窗口的標題欄,邊框,窗口上的其他控件,取消全屏進行逆操作即可。

   4.實現難點

   我覺得最難得是音視頻同步,因爲接收的是實時碼流,對時延要求較高,不能使用較大的緩衝,所以造成諸多問題,解決這些問題發了我相當大一部分時間,這個留作下回再做討論吧。
發佈了12 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章