天天看點

基于MFC的視訊監控系統用戶端實作 ---項目經驗

http://zealove.iteye.com/blog/1277134

基于MFC的視訊監控系統用戶端實作

  • 部落格分類: 
  • 項目總結

一天到晚看面試題,看算法書,堅持了一周左右,人也快扛不住了,需要換換節奏,思考下别的東西啊,已經進入一種混沌無效率的階段了。百度的電話面試遲遲不來,弄的我現在做事情都不時刻注意着手機,都快幻聽了。這種感覺真不好受啊,是以現在開始寫點項目總結。

首先先給CSDN這個部落客做下廣告:http://blog.csdn.net/v_JULY_v

從2010年底開博,寫了很多不錯的文章,文筆思路都挺清晰的。而且看日志發現居然是個專科生,年齡好像跟我也差不多,感覺十分感慨。

進入主題,這個項目是我畢業設計的題目《基于無線網絡的視訊監控用戶端的實作》因為導師這個項目要求保密,是以我隻是做一些思路的記錄,不會貼出任何代碼。其實從本質上說,我覺得資訊的擷取應該是絕對通暢的,這樣的行為都是阻礙知識的傳播。但既然幫導師做事情,這點約定就遵守下把,是以本文章不貼任何圖示。

1.記憶體管理類的設計和實作

   由于是視訊監控系統,是以資料量是不可小觑的,即使以H.264的高壓縮比,要實作D1,乃至720P的視訊,1S要處理的資料量,少則幾十K,大則幾百K,如果記憶體管理系統不夠健壯,直接就崩潰了,更别說堅持上幾天時間的跑了。

   根據視訊資料的特點:資料量大,單向流動,以及用完即可丢棄。是以要設計一個好的記憶體管理類。

   首先需要定義一個記憶體的基類,其中含有指向資料的指針,已經一個整形表示所指記憶體塊的大小,一個令牌。其他具體的緩存類都繼承于這個基類,基類隻定義配置設定記憶體的函數和釋放記憶體的函數并不實作它們,留給子類去實作。這裡就不得不說令牌的作用了,由于緩存對象經常需要被當做參數傳遞,傳遞過程中其實并不複制記憶體的東西,隻是複制指針而已。那每一個對象都含有同一塊記憶體塊的指針,何時釋放資源呢?這時候就需要依靠令牌了,因為視訊資料單向流動,當複制對象的時候,其實之前的對象已經沒有用了,可以忽略他。這裡的機制是含有令牌的對象負責釋放記憶體的資源,在對象複制的過程中傳遞令牌,是以直到最後一個對象也完成使命析構的時候,析構函數才會釋放資源。當然令牌不是唯一實作的方法,比如Windows核心對象的配置設定釋放,還有Python中的垃圾回收都用了另一個機制,就是引用計數(每産生一個指向同一塊記憶體的對象時候,增加計數,析構時候計數減1,然後計數為0時候釋放對象)

   緩存的類型有三種,資料包緩存,幀緩存和圖檔緩存。資料包緩存和幀緩存的處理其實相似,可以分開實作也可以合并,然後圖檔緩存類需要包含一些圖檔的基本資訊,這樣處理起來就很友善了。

   最後是用一個Clist建構一個記憶體池類,然後定義幾個記憶體池,以便後面用就可以了。

2.Windows環境下H.264解碼器方案

   解碼标準是開源的,是以有實力的公司都會實作自己的解碼庫。恩,我們當然不會去做這樣的事情,時間精力都不夠,是以隻能尋找開源的軟體咯。開源H264解碼器裡最有名氣的莫過于ffmpeg了,他不僅僅是264解碼器,而且是音視訊一系列的解決方案,而且是免費的,擷取很友善,還提供SDK,對于小型項目組做視訊處理綽綽有餘了。(偷偷爆料下,據說暴風和QQ影音也是用的他的解碼庫,但沒開源,是以上了ffmpeg的黑名單)由于我接手項目之時有一個解碼器的代碼,當時那個是在網上下的,某牛人将其移植到VC++下的。開始我并沒有研究這部分,直到程式跑通後,發現這個解碼庫的效率實在是不給力。于是開始尋找方案,最後找到一個方法就是Windows下使用MinGW+MSYS 編譯ffmpeg庫,然後連結到VC++裡使用,當時第一次使用外部庫,遇到各種連結錯誤,反正糾結了1周後,各種查資料,一天神奇的連結通過了。可以用了,一試,原來需要幾十毫秒的解碼操作一下變的幾乎不需要時間了,就這樣解決一大問題。

   連結時候讓我明白了Extern “C”到底是神馬。。。還有就是Lib ,DLL到底怎麼用,怎麼生成,當時找了好幾本VC++的書還有Windows程式設計的書去學習這部分内容。終于最後不負衆望啊,但現在也忘記了很多了。

3.網絡傳輸類和連接配接控制類

   網絡部分其實根據需求很明了,一個TCP傳控制指令資料,一個UDP傳視訊資料。都需要用到CSocket類,這是一個非線程安全的,使用起來要小心,尤其跨線程的時候。我盡量避免跨線程,如果一定要跨,就要用到Dettach和Attach這些函數,我沒了解過。。

   首先設計UDP類,比較簡單,直接就是在OnCreate OnRecieve裡實作幾個功能就好了,因為用戶端不需要發送任何東西。隻要接受資料包,然後把收到的資料包放入前面提到的資料包緩沖池就行,沒其他工作了。

   TCP就比較多事情了,但大部分都是接收和處理控制指令。這部分還需要和裝置互動,包括驗證裝置端合法性,傳遞目前接受到的資料量,通過心跳包互相保持連接配接。

   然後是一個主要制類,現在想想,這個類完全可以用單例模式去實作。當時還不懂這些啊。先講了各個部分關系吧。其實每一路視訊都對應一個UDP連接配接(視訊資料)和TCP連接配接(控制指令),(一路視訊在界面上還對應一個Picture Control控件)然後由這個主要類管理所有連接配接,它是協調連接配接和界面顯示的橋梁。(第一天先到這裡,改日繼續)

4.多線程的思考

   并行計算是個熱門的話題,遠的不說,單線程的程式已經不可能适應需求了。就拿這個項目來說,需要支援多路視訊,必然需要多個線程,一路視訊涉及到:資料接收-資料包處理-資料幀的合并-解碼-播放顯示。資料接收和資料包處理可以有CSocket幫你完成,但其他幾個就不行了,尤其是解碼這樣的需要大量耗費CPU時間的,如果将他們三個合并在一個線程中,必然導緻各種延遲和播放不流暢的問題。是以必須分開。

   一個解碼線程,一個合幀線程。線程最大的問題其實不是分割業務邏輯,因為這部分很簡單,最難的是如何做到并發的同時不出現各種問題,比如死鎖,或者讀寫髒資料,或者幹脆就是崩潰了。除此之外還有線程的正常退出,因為線程之間需要利用一些公共的資源,有時候一個線程退出了,他釋放了另一個線程還在使用的資源,結果就崩潰了,這個很常見。是以線程可以說全程都是問題。

    線程由于不是語言相關的,而是系統相關的,C++語言對線程的支援很補給力,必須用系統的,據說新的C++标準将引入Boost的線程庫,如果真的如此用C++寫多線程程式将十分友善了。但現在不行。至于線程的使用,這篇文章寫的非常情況,并且把Linux和Windows的線程函數進行了比較,我就不多說了。

     http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/  多線程程式設計

    我印象中使用的最多的就是WaitForSingleObject 還有CMutex類的Lock和Unlock,當然還有建立線程和退出等函數了。多線程程式最麻煩的就是調試,是以沒寫過的人确實不能了解為什麼線程的複雜和重要性啊。

5.DirectDraw實作繪制BMP位圖

    這個部分,說來慚愧,我并沒有花很多的時間去研究DirectDraw,畢竟當時是實用主義的思想,是以在羅素工作室的網上看到一個直接可用的最簡單的DirectDraw實作BMP位圖的類,然後修修改改就上線了。DirectX是Windows平台強大的圖形工具,以後搞Windows開發的基本都離不開,我心愛的星際1,2都是DirectX開發的。。如果是Linux環境就考慮OpenGL OpenCV。

    這裡也需要提下為什麼必須用DX來實作視訊顯示,因為傳統的Windows繪圖API是高度依靠CPU的計算的。而不使用記憶體顯存的模拟作用來提高繪圖性能,是以它僅僅使用于傳統的窗體程式,對于遊戲-視訊監控,這樣的多圖形處理的程式,完全跟不上節奏了。這個一度成為我那程式的瓶頸,是以當時基本上屬于,遇到一個問題解決一個,而不是一開始就有一個明确的預見性和規劃,防止這類事情的發生。

   推薦網站羅素工作室,有各種視訊處理行業的新聞,還有一些技術文章,幫我解決了很多問題:

   http://www.rosoo.net/

6.各種界面可用性和功能設計

   這部分我就做了幾個基本的,比如全螢幕,比如多路支援,已經動态多路支援,還有就是用Skin++庫美化了下界面,還有正常的,配置管理,本地播放。。。╮(╯▽╰)╭,其實就是想一點做一點的,也沒任何規劃。

總結:這個項目确實很綜合,僅僅用戶端部分就需要解決很多問題,使用到多種程式設計技巧,是以這個項目讓我學習了很多知識,在此需要感謝下老師。恩,先謝國家。是以好的程式員都是寫出來的,如果一直看理論書籍不動手,還不如不看。

繼續閱讀