JAVA基于局域網(wǎng)的聊天室系統(tǒng)(源代碼+論文)
畢業(yè)論文
局域網(wǎng)聊天室系統(tǒng)的設(shè)計與實現(xiàn)
論文作者姓名:申請學位專業(yè):申請學位類別:指導教師姓名(職稱):論文提交日期:
基于局域網(wǎng)的視頻聊天室系統(tǒng)的設(shè)計與實現(xiàn)
摘 要
視頻聊天系統(tǒng)作為一種新型的通信和交流工具,突破了地域的限制,可以提供更為便捷、靈活、全面的音、視頻信息的傳遞和服務(wù),具有極其廣泛的發(fā)展前景。
本文介紹了采用JAVA編程開發(fā)視頻聊天系統(tǒng)的一套比較常用的解決方案。文字聊天采用TCP模式;語音視頻聊天采用UDP模式,在客戶端之間點對點的進行。在該方案中,通過函數(shù)庫VFW來實現(xiàn)視頻捕獲、影像壓縮以及影像播放。微軟公司提供的專門用于視頻捕獲開發(fā)的工具包VFW,為在Windows操作系統(tǒng)中實現(xiàn)視頻捕獲提供了標準的接口,從而大大降低了程序的開發(fā)難度。在視頻傳輸方面,則通過組建視頻幀,將位圖形式的視頻幀壓縮成幀格式的Mpeg4流,傳輸?shù)娇蛻舳撕?,解壓并顯示影像。同時,在本方案中,采用了線程來實現(xiàn)語音錄制和語音回放,最終實現(xiàn)了通過服務(wù)器中轉(zhuǎn)的文字聊天、點對點的語音視頻聊天。
關(guān)鍵詞:文字聊天;VFW;視頻捕獲;視頻傳輸;語音錄制;語音回放
The Design and Realization of?LAN-Based Video Chat Room System
Abstract
As a new tool about communication, video chatting system has broken through geographical restrictions, has provides more convenient, flexible and complete transmission and service. Furthermore, it has a very bright future.
The common solution about how to develop a video chatting system is introduced by the Microsoft Visual C + + 6.0 programming. TCP model is used in the text chatting and UDP for the point-to-point video chats between the Clients. In this plan, Video Capture, Video Compression Manager and DrawDib are realized by the functions of VFW Library. The special kit VFW (Video for Windows) in video capture offered by Microsoft Corporation, has provided a standard interface for video capture in Windows Operating System and thus greatly reduced the hardship of programming. In video transmission aspect, it requires a video frame which is compressed the video frame of bitmap into Mpeg4 steam of frame form. Then it will be decompressed into images since it has been arrived the Client. Meanwhile, the thread is used to achieve audio recording and replaying. Finally, it has realized the text chatting through a server to transit, the point-to-point audio and video chats.
Key words:?text chatting; VFW; Video Capture; video transmission; audio recording; audio playing
目 錄
論文總頁數(shù):24頁
1引言11
1.1課題背景11
1.2國內(nèi)外研究現(xiàn)狀11
2理論知識介紹11
2.1VFW簡介11
2.2線程的實現(xiàn)方法44
3需求分析55
3.1軟硬件環(huán)境55
3.2需求分析55
4系統(tǒng)結(jié)構(gòu)77
4.1硬件結(jié)構(gòu)77
4.2軟件結(jié)構(gòu)77
4.2.1功能需求77
4.2.2系統(tǒng)功能模塊圖88
4.3系統(tǒng)各模塊流程圖88
5系統(tǒng)的詳細設(shè)計1010
5.1文字聊天1010
5.1.1TCP套接字的運用1010
5.1.2文字聊天實現(xiàn)1111
5.2語音視頻聊天1313
5.2.1UDP套接字的運用1313
5.2.2視頻的捕獲1414
5.2.3捕獲窗口1616
5.2.4視頻捕獲驅(qū)動1818
5.2.5語音錄制1818
5.2.6語音回放1919
5.2.7視音頻的傳輸2020
結(jié) 論2121
參考文獻2222
致 謝2323
聲 明2424
引言
課題背景
隨著Internet的不斷發(fā)展普及,網(wǎng)絡(luò)通訊越來越被千家萬戶所接受,成為人們生活中的一部分。網(wǎng)絡(luò)聊天已和手機等一樣,成為人們運用最為廣泛的通信工具之一。本畢業(yè)設(shè)計的目的主要是為了滿足人們通訊交流的便捷,實現(xiàn)靈活、全面的音、視頻信息的傳遞和服務(wù)。模擬騰訊公司的QQ聊天軟件,開發(fā)一個多功能的聊天系統(tǒng)軟件,本畢業(yè)設(shè)計主要實現(xiàn)視頻語音聊天、文字聊天等功能。國內(nèi)外研究現(xiàn)狀
隨著網(wǎng)絡(luò)寬帶業(yè)務(wù)的推廣與普及,加之視頻產(chǎn)品設(shè)備(如攝像頭、耳機、麥克風等)的成熟,普通用戶可以輕松地借助網(wǎng)絡(luò)視頻通訊軟件,實現(xiàn)“面對面”的網(wǎng)絡(luò)交流。信息的無限量擴大,交通工具的便捷,視頻技術(shù)的充分應用等導致了行業(yè)間競爭的全球化,這就要求現(xiàn)代部門、企業(yè)要具備更加靈敏的神經(jīng),更扁平化的管理,更快速的反應和決策,更貼切的市場宣傳和服務(wù)。所有這一切是由信息技術(shù)的發(fā)展所帶來的,同樣也要求有先進的信息技術(shù)來提高部門、企業(yè)的競爭力?,F(xiàn)代通訊已經(jīng)是越來越普及了,必須有效合理的運用視頻產(chǎn)品類設(shè)備來提高信息的傳遞和交流。在同一個局域網(wǎng)中,充分、合理的運用攝像頭、耳機、麥克風等設(shè)備來實現(xiàn)文字聊天和語音視頻聊天更是我們生活、學習、工作的便利所在。
理論知識介紹
VFW簡介
VFW是Microsoft 1992年推出的關(guān)于數(shù)字視頻的一個軟件包,它能使應用程序數(shù)字化并播放從傳統(tǒng)模擬視頻源得到的視頻剪輯。VFW的一個關(guān)鍵思想是播放時不需要專用硬件,為了解決數(shù)字視頻數(shù)據(jù)量大的問題,需要對數(shù)據(jù)進行壓縮。它引進了一種叫AVI的文件標準,該標準未規(guī)定如何對視頻進行捕獲、壓縮及播放,僅規(guī)定視頻和音頻該如何存儲在硬盤上,以及在AVI文件中交替存儲視頻幀和與之相匹配的音頻數(shù)據(jù)。VFW給程序員提供VBX和AVICap窗口類的高級編程工具,使程序員能通過發(fā)送消息或設(shè)置屬性來捕獲、播放和編輯視頻剪輯。用戶不必專門安裝VFW,在安裝Windows時,安裝程序會自動地安裝配置視頻所需的組件,如設(shè)備驅(qū)動程序、視頻壓縮程序等。
VFW主要由以下六個模塊組成:
AVICAP.DLL:包含了執(zhí)行視頻捕獲的函數(shù),它給AVI文件、I/O和視頻音頻設(shè)備驅(qū)動程序提供一個高級接口;
MSVIDEO.DLL:用一套特殊的DrawDib函數(shù)來處理屏幕上的視頻操作;
MCIAVI.DRV:此驅(qū)動程序包括對VFW的MCI命令的解釋器;
AVIFILE.DLL:支持由標準多媒體I/O(mmio)函數(shù)提供的更高的命令來訪問AVI文件;
壓縮管理器(ICM):管理用于視頻壓縮/解壓縮的編解碼器(CODEC);
音頻壓縮管理器ACM:提供與ICM相似的服務(wù),不同的是它適于波形音頻。
Visual C++在支持VFW方面提供有vfw32.lib、msacm32.lib、winmm.lib等庫。特別是它提供了功能強大、簡單易行、類似于MCIWnd的窗口類AVICap。AVICap為應用程序提供了一個簡單的、基于消息的接口,使之能訪問視頻和波形音頻硬件,并能在將視頻流捕獲到硬盤上的過程中進行控制。
AVICap支持實時的視頻流捕獲和單幀捕獲,并提供對視頻源的控制。雖然MCI也提供數(shù)字視頻服務(wù),比如,它為顯示AVI文件的視頻提供了AVIVideo命令集,為視頻疊加提供了overlay命令集,但這些命令主要是基于文件的操作,不能滿足實時地直接從視頻緩存中獲取數(shù)據(jù)的要求。對于使用沒有視頻疊加能力的捕獲卡的PC機來說,用MCI提供的命令集是無法捕獲視頻流的。而AVICap在捕獲視頻方面具有一定的優(yōu)勢,它能直接訪問視頻緩沖區(qū),不需要生成中間文件,實時性很強,效率很高。同時,它也可將數(shù)字視頻捕獲到文件。
在視頻捕獲之前需要創(chuàng)建一個捕獲窗,所有的捕獲操作及其設(shè)置都以它為基礎(chǔ)。用AVICap窗口類創(chuàng)建的窗口(通過capCreateCaptureWindow函數(shù)創(chuàng)建)被稱為“捕獲窗”,其窗口風格一般為WS_CHILD和WS_VISIBLE。實際上,捕獲窗類似于標準控制(如按鈕、列表框等)。捕獲窗具有下列功能:
將視頻流和音頻流捕獲到一個AVI文件中;
動態(tài)地同視頻和音頻輸入器件連接或斷開;
以O(shè)verlay或Preview模式對輸入的視頻流進行實時顯示;
在捕獲時可指定所用的文件名并能將捕獲文件的內(nèi)容拷貝到另一個文件;
設(shè)置捕獲速率;
顯示控制視頻源、視頻格式、視頻壓縮的對話框;
創(chuàng)建、保存或載入調(diào)色板;
將圖像和相關(guān)的調(diào)色板拷貝到剪貼板;
將捕獲的一個單幀圖像保存為DIB格式的文件。
AVICap在顯示視頻時提供的兩種模式:
(A)預覽(Preview)模式:該模式使用CPU資源,視頻幀先從捕獲硬件傳到系統(tǒng)內(nèi)存,接著采用GDI函數(shù)在捕獲窗中顯示。在物理上,這種模式需要通過VGA卡在監(jiān)視器上顯示。
(B)疊加(Overlay)模式:該模式使用硬件疊加進行視頻顯示,疊加視頻的顯示不經(jīng)過VGA卡,疊加視頻的硬件將VGA的輸出信號與其自身的輸出信號合并,形成組合信號顯示在計算機的監(jiān)視器上。只有部分視頻捕獲卡才具有視頻疊加能力。
靈活編寫AVICap提供的回調(diào)函數(shù)還可滿足一些特殊需求。比如,將宏capCaptureSequenceNoFile同用capSetCallbackOnVideoStream登記的回調(diào)函數(shù)一起使用,可使應用程序直接使用視頻和音頻數(shù)據(jù)。在視頻聊天的應用程序中可利用這一點來獲得視頻幀,回調(diào)函數(shù)將捕獲的圖像傳到遠端的計算機。應用程序可用捕獲窗來登記回調(diào)函數(shù)(由用戶編寫,而由系統(tǒng)調(diào)用),以便在發(fā)生下列情況時,它能通知應用程序,作出相應的反應:捕獲窗狀態(tài)改變;出錯;視頻幀和音頻緩存可以使用;在捕獲過程中,其它應用程序處于讓步(Yield)地位。
視頻捕獲編程也要用到涉及視頻捕獲的結(jié)構(gòu)、宏、消息和函數(shù)。令人高興的是,發(fā)送AVICap窗口消息所能完成的功能都能調(diào)用相應的宏來完成。例如,SendMessage(hWndCap,WM_CAP_DRIVER_CONNECT,0,0L)與capDriverConnect(hWndCap,0)的作用相同,都是將創(chuàng)建的捕獲窗同視頻輸入器件連接起來。
視頻部分主要是利用Video Capture函數(shù)庫來獲取影像的。Video Capture主要提供下列功能:連接驅(qū)動程序;獲取影像、聲音資料,并顯示在屏幕上或者是存成AVI文件;獲取單張影像顯示在屏幕上,拷貝至剪貼簿,或者是存成DIB(Device-Independent Bitmap)文件。
Video Capture的主要結(jié)構(gòu):
結(jié)構(gòu)體CAPTUREPARAMS主要包含一些獲取圖像的參數(shù):DWORD dwRequestMicroSecPerFrame代表相鄰兩個frame的獲取時間間隔;BOOL fYield值為TRUE,則表示W(wǎng)indows會以另一個thread來捕獲影像,值為FALSE,程序會在捕捉影像后顯示忙碌狀態(tài);BOOL fCaptureAudio其值表示是否需要同時獲取聲音資料。
結(jié)構(gòu)體BITMAPINFO和點陣圖有關(guān),主要定義了影像獲取之后顯示在屏幕上、存儲在文件中的格式,它包含兩個成員:BITMAPINFOHEADER bmiHeader描述影像性質(zhì)的結(jié)構(gòu),其成員記載了影像的大小、顏色深度和壓縮的方式,該成員在Video Capture、Video Compression Manager和DrawDib函數(shù)庫中,以及有關(guān)于點陣圖的應用中;RGBQUAD bmiColors指向color table第一個元素的位置。
結(jié)構(gòu)體COMPVARS主要是記錄所有和壓縮相關(guān)的信息,重要的成員:DWORD fccHandler為compressor句柄;LPBITMAPINFO lpbiIn指向待壓縮影像BITMAPINFO的指標;LPBITMAPINFO lpbitOut:指向壓縮完影像BITMAPINFO的指標;LONG lKey代表key-frame rate,而所謂key frame是指此frame在解壓縮時不需要依賴前面的frame;LONG lQ代表影像壓縮后的品質(zhì),取值為1~10000的整數(shù)。
Video Compression Functions主要記錄壓縮功能相關(guān)的信息,其包含的比較重要的成員:ICLocate輸入指向壓縮前后BITMAPINFO的指標,以及欲使用的codecs;ICCompressorChoose呼叫一個系統(tǒng)內(nèi)建的對話,其中包含所有可能使用的codes以及其相關(guān)參數(shù);ICCompressQuery詢問compressor是否支持某種壓縮方式,輸入?yún)?shù)為compressor handle及指向壓縮前后BITMAPINFO的指標,此函數(shù)會傳回詢問結(jié)果;ICCompressBegin要求系統(tǒng)準備相關(guān)資源以供壓縮之用;ICCompress壓縮某個frame;ICCompressEnd歸還相關(guān)資源給系統(tǒng);ICDompressQuery詢問decompressor是否支持某種解壓縮方式;ICDompressBegin要求系統(tǒng)準備相關(guān)資源以供解壓縮之用;ICDompress解壓縮某一個frame;ICDompressEnd歸還相關(guān)資源給系統(tǒng);ICDompressFree歸還COMPVARS所占用的資源。
線程的實現(xiàn)方法
線程是一個獨立的執(zhí)行流,是進程內(nèi)部的一個獨立的執(zhí)行單元,相當于一個子程序,它對應于Visual C++中的CWinThread類對象。單獨一個執(zhí)行程序運行時,缺省地包含了一個主線程,主線程以函數(shù)地址的形式出現(xiàn),提供程序的啟動點,當主線程終止時,進程也隨之終止。根據(jù)實際需要,應用程序可以分解成許多獨立執(zhí)行的線程,每個線程并行的運行在同一進程中。
一個進程中的所有線程都在該進程的虛擬地址空間中,使用該進程的全局變量和系統(tǒng)資源。操作系統(tǒng)給每個線程分配不同的CPU時間片,在某一個時刻,CPU只執(zhí)行一個時間片內(nèi)的線程,多個時間片中的相應線程在CPU內(nèi)輪流執(zhí)行,由于每個時間片時間很短,所以對用戶來說,仿佛各個線程在計算機中是并行處理的。操作系統(tǒng)是根據(jù)線程的優(yōu)先級來安排CPU的時間,優(yōu)先級高的線程優(yōu)先運行,優(yōu)先級低的線程則繼續(xù)等待。
Windows提供了兩種線程:用戶界面線程和工作線程(又稱為后臺線程)。用戶界面線程通常用來處理用戶的輸入并響應各種事件和消息,其實,應用程序的主執(zhí)行線程CWinApp對象就是一個用戶界面線程,當應用程序啟動時自動創(chuàng)建和啟動,同樣它的終止也意味著該程序的結(jié)束,進程終止。工作線程用來執(zhí)行程序的后臺處理任務(wù),比如計算、調(diào)度、對串口的讀寫操作等,它和用戶界面線程的區(qū)別是它不用從CWinThread類派生來創(chuàng)建,對它來說最重要的是如何實現(xiàn)工作線程任務(wù)的運行控制函數(shù)。工作線程和用戶界面線程啟動時要調(diào)用同一個函數(shù)的不同版本;一個進程中的所有線程共享它們父進程的變量,但同時每個線程可以擁有自己的變量。
這里主要介紹用戶界面線程的運用:
線程的啟動
創(chuàng)建一個用戶界面線程,首先要從類CwinThread產(chǎn)生一個派生類,同時必須使DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE來聲明和實現(xiàn)這個CwinThread派生類。第二步是根據(jù)需要重載該派生類的一些成員函數(shù)如:ExitInstance()、InitInstance()、OnIdle()、PreTranslateMessage()等函數(shù)。最后調(diào)用AfxBeginThread()函數(shù)的一個版本:CWinThread* AfxBeginThread (CRuntimeClass* pThreadClass,int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL)啟動該用戶界面線程,其中第一個參數(shù)為指向定義的用戶界面線程類指針變量,第二個參數(shù)為線程的優(yōu)先級,第三個參數(shù)為線程所對應的堆棧大小,第四個參數(shù)為線程創(chuàng)建時的附加標志,缺省為正常狀態(tài),如為CREATE_SUSPENDED則線程啟動后為掛起狀態(tài)。線程的優(yōu)先級
CwinThread類的成員函數(shù)用于線程優(yōu)先級的操作:
int GetThreadPriority();
BOOL SetThradPriority()(int nPriority);線程的掛起和恢復
CWinThread類中包含了應用程序掛起和恢復它所創(chuàng)建的線程的函數(shù),其中SuspendThread()用來掛起線程,暫停線程的執(zhí)行;ResumeThread()用來恢復線程的執(zhí)行。如果你對一個線程連續(xù)若干次執(zhí)行SuspendThread(),則需要連續(xù)執(zhí)行相應次的ResumeThread()來恢復線程的運行。結(jié)束線程
終止線程有三種途徑,線程可以在自身內(nèi)部調(diào)用AfxEndThread()來終止自身的運行;可以在線程的外部調(diào)用BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)來強行終止一個線程的運行,然后調(diào)用CloseHandle()函數(shù)釋放線程所占用的堆棧;第三種方法是改變?nèi)肿兞?,使線程的執(zhí)行函數(shù)返回,則該線程終止。
需求分析
軟硬件環(huán)境
電腦兩臺以上,分別配有攝像頭、麥克風、音箱或耳機等外部設(shè)備;Windows XP系統(tǒng),Microsoft Visual Studio 6.0編程開發(fā)系統(tǒng)等。需求分析
在同一個局域網(wǎng)中,如何根據(jù)自身業(yè)務(wù)的要求,量身定制,對視頻設(shè)備進行合理搭配,選擇一套合理的視頻聊天室系統(tǒng)。如何來滿足局域網(wǎng)內(nèi)部用戶的通訊要求,在考慮到網(wǎng)絡(luò)帶寬的同時,提高視頻清晰度,動態(tài)畫面的流暢,語音的實時傳輸?shù)?,正是現(xiàn)代社會通訊所必需的。設(shè)計本系統(tǒng)時,分析網(wǎng)絡(luò)承載、整個系統(tǒng)結(jié)構(gòu)的組建等是實現(xiàn)局域網(wǎng)文字聊天和語音視頻聊天所必需的。
文字、語音視頻聊天作為一種廣泛的網(wǎng)絡(luò)應用對其基礎(chǔ)的承載網(wǎng)絡(luò)環(huán)境有著較高的網(wǎng)絡(luò)要求。其中應重點考慮的是網(wǎng)絡(luò)的帶寬情況、端到端的時延、時延抖動、丟包率等問題。
網(wǎng)絡(luò)帶寬需求,視頻聊天對網(wǎng)絡(luò)的帶寬需求為“視頻帶寬+IP包頭開銷”,計算方法為:網(wǎng)絡(luò)帶寬 = 視頻帶寬 × 1.2。
端到端的時延,網(wǎng)絡(luò)傳輸不可避免的會發(fā)生傳輸時延,通常建議視頻聊天的通用時延小于150ms。
時延抖動,由于音頻/視頻的傳輸為實時的交互,因此網(wǎng)絡(luò)的時延抖動更為重要,一般,視頻聊天的時延抖動控制在50ms內(nèi)。
丟包率,網(wǎng)絡(luò)數(shù)據(jù)傳輸經(jīng)常會出現(xiàn)丟包現(xiàn)象,視頻傳輸過程中數(shù)據(jù)丟包嚴重的話會影響在線視頻聊天質(zhì)量。因此,在設(shè)計上應將網(wǎng)絡(luò)上的丟包率控制在1%以內(nèi)。
視頻聊天對實時性要求較高的網(wǎng)絡(luò)應用,作為其基礎(chǔ)的承載網(wǎng)絡(luò)有較高的寬帶和對網(wǎng)絡(luò)中的業(yè)務(wù)流量有較高的控制能力。而視頻聊天系統(tǒng)本身對帶寬的要求為62kbit/s~2Mbit/s,但是為了滿足流暢的視音頻效果,要求帶寬不低于384kbit/s。
文字、視頻聊天的功能和應用效果體現(xiàn)在客戶端,而服務(wù)器端則是必不可少的,對于系統(tǒng)的需求分析在系統(tǒng)設(shè)計的過程中應該明確、細致:
文字聊天:首先啟動服務(wù)器端,當用戶啟動客戶端時,用服務(wù)器保存的用戶名和密碼來驗證客戶是否已經(jīng)登錄到服務(wù)器。只有當有兩個以上的用戶啟動客戶端時,才可以進行文字聊天,聊天內(nèi)容要經(jīng)過服務(wù)器中轉(zhuǎn),分別在服務(wù)器端和兩個聊天的客戶端顯示聊天。
語音視頻聊天:在有兩個客戶在線的情況下,才能進行語音視頻聊天。兩個用戶要進行語音視頻聊天時,一個用戶選中另一個用戶的用戶名,根據(jù)該用戶名在后臺鏈表中的對應IP地址查找用戶并請求視頻連接。當雙方確認視頻連接后就進行視頻傳輸,并顯示在客戶端,同時用線程實現(xiàn)語音錄制和回放。這樣,兩個用戶就實現(xiàn)了點對點的語音視頻聊天。在進行語音視頻聊天的過程中,不能再與其它用戶進行語音視頻聊天,但能夠與其它用戶進行文字聊天。
系統(tǒng)結(jié)構(gòu)
硬件結(jié)構(gòu)
該系統(tǒng)采用的是Server/Client結(jié)構(gòu),服務(wù)器端是一臺PC機,而客戶端是PC機和一個數(shù)字攝像頭、耳機和麥克風。它們進行文字聊天時,要經(jīng)過服務(wù)器進行中轉(zhuǎn),而當進行語音視頻聊天時是客戶端與客戶端之間直接進行的點對點的連接,它們之間的網(wǎng)絡(luò)拓撲結(jié)構(gòu)如圖1。在圖中,為了簡便,沒有畫出麥克風、音箱或耳機等外部設(shè)備。
圖1 網(wǎng)絡(luò)拓撲結(jié)構(gòu)圖
軟件結(jié)構(gòu)
功能需求
通過需求調(diào)研并分析,確定系統(tǒng)具備的基本功能,包括:文字聊天、語音視頻聊天。
文字聊天:
文字聊天采用的是TCP模式,包括服務(wù)器端和客戶端。首先啟動服務(wù)器端,客戶端通過用戶名和密碼登錄服務(wù)器,服務(wù)器響應客戶端登錄并提示有用戶登錄,此時兩個用戶就可以進行文字聊天,在文字聊天時通過服務(wù)器中轉(zhuǎn),而每個用戶可以同時與多個用戶進行文字聊天。當有用戶退出時,服務(wù)器做出響應,提示在線用戶,××用戶下線。語音視頻聊天:
語音視頻聊天時采用的是UCP模式,客戶端與客戶端點對點的進行,不需要經(jīng)過服務(wù)器端中轉(zhuǎn)。在文字聊天的基礎(chǔ)上,客戶端之間自行處理的語音視頻聊天,運用VFW函數(shù)庫中的函數(shù)對USB口輸入的數(shù)字視頻信息進行相關(guān)處理,比如:視頻捕獲、影像壓縮以及影像播放等,同時利用線程來處理聲音部分的錄制、回放等。A客戶端向B客戶端請求語音視頻聊天是通過B客戶端的用戶名來獲得B客戶端的IP地址,并向B客戶端發(fā)送語音視頻聊天請求,當B客戶端接受后捕獲視頻,并進行壓縮傳輸?shù)紸客戶端解壓并進行顯示,在B客戶端接受視頻的同時,A客戶端也捕獲視頻,壓縮傳輸?shù)紹客戶端解壓并進行顯示。
系統(tǒng)功能模塊圖
該系統(tǒng)分為服務(wù)器端和客戶端,完成了文字聊天和語音視頻聊天,使用上只有文字聊天時才會通過服務(wù)器端,而對于語音視頻聊天就只需要對整個在線客戶端兩兩之間進行點對點的視頻聊天。而在語音視頻時包括了視頻捕獲、視頻壓縮、解壓縮、語音錄制、語音回放以及視頻傳輸?shù)?。整個系統(tǒng)的功能模塊圖如圖2。
圖2 系統(tǒng)功能模塊圖
系統(tǒng)各模塊流程圖
在整個系統(tǒng)中主要運行兩個功能:圖3 文字聊天流程圖和圖4 語音視頻聊天流程圖。
圖3 文字聊天流程圖
圖4 語音視頻聊天流程圖
系統(tǒng)的詳細設(shè)計
文字聊天
TCP套接字的運用
在文字聊天時,服務(wù)器端與客戶端的連接是采用的TCP套接節(jié)進行連接。TCP套接字的使用如圖5。創(chuàng)建CSocket對象CSocketServer來處理服務(wù)器端與客戶端的連接,CSocket繼承于CasyncSocket,是Windows Socket API的高層抽象。CSocket通常和CsocketFile以及Carchive類混合使用,這兩個類負責數(shù)據(jù)的發(fā)送和接收。要使用CSocket對象,首先要調(diào)用構(gòu)造函數(shù),然后調(diào)用Create函數(shù)創(chuàng)建一個Socket句柄。CSocket函數(shù)缺省是創(chuàng)建一個流Socket;如果沒有使用CArchive類,那么還可以創(chuàng)建一個數(shù)據(jù)報Socket。服務(wù)器端調(diào)用Accept,客戶端調(diào)用Connect,然后創(chuàng)建一個CsocketFile去關(guān)聯(lián)CSocket。接下來的操作可以創(chuàng)建CArchive對象關(guān)聯(lián)CsocketFile,以用來發(fā)送和接收數(shù)據(jù)。
圖5 TCP套接字的使用
文字聊天實現(xiàn)
ChatServer服務(wù)器運行時,利用一個CSocket對象CSocketServer啟動服務(wù)器,用函數(shù)gethostname來獲得服務(wù)器端主機名和IP,同時在服務(wù)器對話框中顯示服務(wù)器IP,并將分配的固定端口號8123顯示在對話框中。用一個list列表顯示在線用戶,隨時更新用戶登錄情況,用一個edit box顯示客戶端的聊天內(nèi)容以及系統(tǒng)提示消息。每一個ChatClient客戶端啟動時,利用服務(wù)器內(nèi)定的用戶號和密碼來登錄(如圖6)。在整個系統(tǒng)中,利用鏈表來處理所有的用戶信息:當有用戶登錄時,在鏈表尾部加入該用戶信息;當用戶下線時,在該鏈表中刪除用戶,并提示所有用戶,該用戶下線。在對鏈表進行操作的同時,要更新list列表中的信息。
圖6 用戶登錄界面
ChatServer服務(wù)器端響應客戶端文字聊天時的中轉(zhuǎn)情況如圖7。
圖7 服務(wù)器響應文字聊天信息中轉(zhuǎn)
ChatClient客戶端兩兩間進行文字聊天時,發(fā)送信息的處理函數(shù)如下:
void CChatClientDlg::OnChatBtSend() //發(fā)送信息按鍵
{
if( !m_bConnect)
{
SetMessageBox("請連接服務(wù)器!\r\n");
return ;
}
CString str;
CString szUserName;
CMesg msg;
GetDlgItemText(IDC_MESSAGE,str);
GetDlgItemText(IDC_USERNAME,szUserName);
if( str.GetLength() <= 0 )
{
SetMessageBox("請輸入想要發(fā)送的信息!\r\n");
return ;
}
if ( szUserName.GetLength() <= 0)
{
SetMessageBox("請選擇說話對象!\r\n");
return ;
}
//消息封裝
msg.m_szCommand.Format("Message");
msg.m_szRecObject.Format(szUserName);
msg.m_szText.Format(str);
m_csClient->SendM(&msg);
AddReceiver(szUserName , true);
AddChatMessage(str);
}
在聊天兩個客戶端的信息情況如圖8和圖9。
圖8 接收文字信息
圖9 發(fā)送文字信息
語音視頻聊天
UDP套接字的運用
在實現(xiàn)語音視頻聊天時,采用的是基于UDP套接字的點對點模式,而UDP面向的是無連接的數(shù)據(jù)服務(wù),其套接字的使用如圖10所示。
圖10 UDP套接字的使用
視頻的捕獲
利用VFW接口,視頻捕獲可以分為以下幾個步驟:
建立視頻采集窗口:該窗口用來接收視頻捕捉驅(qū)動程序傳來的數(shù)據(jù)和消息。
連接視頻驅(qū)動程序:將建立的視頻捕捉窗口與視頻設(shè)備驅(qū)動程序相連。
視頻捕獲初始化。
視頻捕捉設(shè)置:VFW下視頻捕捉參數(shù)的設(shè)置可以通過調(diào)用函數(shù)或彈出對話框的形式來實現(xiàn)。一般視頻驅(qū)動程序允許設(shè)置的參數(shù)包括視頻源選擇、視頻格式、視頻顯示格式等。
設(shè)置回調(diào)函數(shù):通過回調(diào)函數(shù)來通知程序視頻事件的發(fā)生,比如捕捉一幀圖像成功的消息,捕捉出錯的消息等。
結(jié)束捕捉:結(jié)束捕捉是應該有一些清除工作。如釋放分配的內(nèi)存,斷開捕捉窗口與視頻捕捉驅(qū)動程序的連接,清除視頻捕捉窗口等。
窗口類為捕獲數(shù)字視頻流及其相關(guān)操作提供了很大的方便,靈活編寫其中的回調(diào)函數(shù)可滿足實時視頻傳輸?shù)男枰鐟贸绦蚩芍苯訌木彌_中取得數(shù)字視頻并對其進行壓縮編碼后實時地傳到遠端的客戶端。
在VC++中,采用VFW技術(shù),客戶端通過capSetCallbackOnFrame()注冊回調(diào)函數(shù),當采集卡采集到一幅圖像后,系統(tǒng)就會自動調(diào)用回調(diào)函數(shù),然后再回調(diào)函數(shù)中使用ICSeqCompressFrame()函數(shù)進行壓縮。然后再通過Winsock將壓縮后的數(shù)據(jù)發(fā)送到另一客戶端。該客戶端接收完一幀以后,交給ICDecompress()解壓,最后用SetDIBitsToDevice()將圖像顯示出來。
基本的捕獲設(shè)置包括設(shè)置捕獲速度(每秒捕獲多少幀)、是否同時捕獲聲頻、捕獲緩沖、允許最大丟失多少幀和是否使用DOS內(nèi)存,以及使用鍵盤的哪個鍵或鼠標的哪個鍵來終止捕獲等內(nèi)容,這些設(shè)置使用CAPTUREPARAMS結(jié)構(gòu)來描述,capCaptureGetSetup宏來得到當前的設(shè)置,然后改變此結(jié)構(gòu)的成員變量,再使用capCaptureSetSetup宏設(shè)置新的設(shè)置。
設(shè)置捕獲速度,通過使用capCaptureGetSetup宏來得到當前的捕捉速度,將當前的捕捉速度保存在CAPTUREPARAMS結(jié)構(gòu)的dwRequestMicroSecPerFrame成員變量中,也可以通過設(shè)置此變量來改變當前設(shè)置值。
設(shè)置終止捕獲,同樣通過使用capCaptureGetSetup宏來得到當前的設(shè)置,當前按鍵設(shè)置保存在CAPTUREPARAMS結(jié)構(gòu)的vKeyAbort成員中,鼠標設(shè)置保存在fAbortLeftMouse和fAbortRightMouse成員中,通過修改可以設(shè)置新的熱健或者鼠標左右鍵,修改完成后,使用capCaptureSetSetup宏來進行更新。
捕獲的時間限制,用CAPTUREPARAMS結(jié)構(gòu)中的fLimitEnabled表示捕獲是否有時間的限制,wTimeLimit用來設(shè)置指示捕獲最大的持續(xù)時間,其單位為秒。使用capCaptureGetSetup宏來得到當前的設(shè)置值。
下面程序為設(shè)置CAPTUREPARAMS結(jié)構(gòu)的實現(xiàn)代碼:
BOOL VideoCapture::SetCapturePara()
{
CAPTUREPARMS CapParms={0};
capCaptureGetSetup(m_capwnd,&CapParms,sizeof(CapParms));
//得到當前的捕獲速度
CapParms.fAbortLeftMouse = FALSE;
CapParms.fAbortRightMouse = FALSE;
CapParms.fYield = TRUE;
CapParms.fCaptureAudio = FALSE;
CapParms.wPercentDropForError = 80;
if(!capCaptureSetSetup(m_capwnd,&CapParms,sizeof(CapParms)))
{
//log.WriteString("\n Failed to set the capture parameters ");
return FALSE;
}
// Set Video Format
capGetVideoFormat(m_capwnd,&m_bmpinfo,sizeof(m_bmpinfo));
m_bmpinfo.bmiHeader.biWidth=IMAGE_WIDTH;
m_bmpinfo.bmiHeader.biHeight=IMAGE_HEIGHT;
BOOL ret=capSetVideoFormat(m_capwnd,&m_bmpinfo,sizeof(m_bmpinfo));
//log.WriteString("\n Video parameters set properly");
return ret;
}
//終止一個捕獲任務(wù)
BOOL VideoCapture::StopCapture()
{
capCaptureStop(m_capwnd);
capCaptureAbort(m_capwnd);
Sleep(500);
return TRUE;
}
捕獲窗口
在捕獲前必須創(chuàng)建一個捕獲窗口(Capture Widnow),下面介紹有關(guān)捕獲窗口的情況:創(chuàng)建一個AVICap捕獲窗口,用capCreateCaptureWindow函數(shù)并返回一個句柄。將捕獲窗口連接至捕獲設(shè)備,用capDriverConnect函數(shù)來使一個捕獲窗口與一個捕獲設(shè)備連接或關(guān)聯(lián)連接上后,就可以通過捕獲窗口向捕獲設(shè)備發(fā)送各種消息,可以使用函數(shù)capGetDriverDescription來獲得已安裝的捕獲設(shè)備名稱及版本,將其列舉在實現(xiàn)程序過程中。再利用capDriverGetName函數(shù)來得到捕獲設(shè)備的名稱將獲得的版本發(fā)送到capDriverGetVersion。如果斷開捕獲窗口與捕獲設(shè)備的連接用capDriverDisconnect。
捕獲窗口的狀態(tài),用capGetStatus函數(shù)來獲得當前捕獲窗口的狀態(tài),得到一個CAPSTATUS結(jié)構(gòu)的拷貝。該結(jié)構(gòu)的內(nèi)容包含了圖片的尺寸、卷軸的當前位置、overlay和preview是否已設(shè)置。由于其信息是動態(tài)的,每當捕獲的視頻流的尺寸發(fā)生改變,程序應該在獲取捕獲設(shè)備的視頻格式以后及時進行刷新。而捕獲窗口尺寸的改變并不影響實際的捕獲視頻流的尺寸。該尺寸由視頻捕獲設(shè)備的格式和視頻對話框決定。
//捕獲窗口
BOOL VideoCapture::Initialize()
{
char devname[128]={0},devversion[128]={0};
int index=0;
BOOL ret = TRUE, ret1 = TRUE, ret2 = TRUE, ret3 = TRUE;
TRACE("VideoCapture::Initialize\n");
//創(chuàng)建一個AVICap捕獲窗口
m_capwnd = capCreateCaptureWindow("Capture",WS_POPUP,0,0,1,1,0,0);
if(!m_capwnd)
{
return FALSE;
}
//connect callback functions
ret = capSetUserData(m_capwnd,this);
//Change destroy functions also........
ret1 = capSetCallbackOnVideoStream(m_capwnd,OnCaptureVideo);
//得到已安裝的捕獲設(shè)備的名稱及版本
ret2 = capGetDriverDescription(index,devname,100,devversion,100);
// Connect to webcam driver
//使一個捕獲窗口與一個捕獲設(shè)備連接或關(guān)聯(lián)
ret3 = capDriverConnect(m_capwnd,index);
if(!(ret && ret1 && ret2 && ret3))
{
// Device may be open already or it may not have been
// closed properly last time.
AfxMessageBox("Unable to open Video Capture Device");
//log.WriteString("\n Unable to connect driver to the window");
m_capwnd=NULL;
return FALSE;
}
// Set the capture parameters
if(SetCapturePara()==FALSE)
{
// log.WriteString("\n Setting capture parameters failed");
capDriverDisconnect(m_capwnd); //使捕獲窗口與一個捕獲設(shè)備斷開
return FALSE;
}
return TRUE;
}視頻捕獲驅(qū)動
視頻捕獲必須具有視頻捕獲驅(qū)動才能進行,其相關(guān)內(nèi)容如下:
視頻捕獲驅(qū)動的性能,capDriverGetCap函數(shù)得到當前連接視頻驅(qū)動的硬件性能,該信息保存在CAPDRIVERCAPS結(jié)構(gòu)中;視頻對話框,每個視頻驅(qū)動能夠提供4個對話框來控制視頻捕獲和數(shù)字化處理視頻對話框定義的視頻壓縮率和圖像品質(zhì)等。視頻對話框都在視頻捕獲驅(qū)動中定義。這個四個對話框分別為:Video Source對話框用于控制選擇視頻來源(capDlgVideoSource);Video Format對話框定義視頻幀的尺寸和精度,以及視頻捕獲卡的壓縮設(shè)置(capDlgVideoFormat);Video Display對話框控制在視頻捕獲期間相關(guān)顯示器上的顯示(capDlgVideoDisplay);Video Compression對話框控制壓縮和圖像品質(zhì)(caoDlgVideoCompression)。語音錄制
在音頻的錄制和播放時,采用的用戶界面線程來處理,是CWinThread對象,根據(jù)前面線程的介紹,一步一步的來實現(xiàn)。錄音用的一個CWinThread對象CAudioRec來實現(xiàn),部分實現(xiàn)代碼:
LRESULT CAudioRec::OnStartRecording(WPARAM wp, LPARAM lp)
{
if(recording)return FALSE;
//打開錄音設(shè)備
MMRESULT mmReturn = ::waveInOpen( &m_hRecord, WAVE_MAPPER,
&m_WaveFormatEx, ::GetCurrentThreadId(), 0, CALLBACK_THREAD);
if(mmReturn!=MMSYSERR_NOERROR )return FALSE;
if(mmReturn==MMSYSERR_NOERROR )
{
for(int i=0; i < MAXRECBUFFER ; i++)
{
//為錄音設(shè)備準備緩存
mmReturn = ::waveInPrepareHeader(m_hRecord,
rechead[i], sizeof(WAVEHDR));
//給輸入設(shè)備增加一個緩存
mmReturn = ::waveInAddBuffer(m_hRecord,
rechead[i], sizeof(WAVEHDR));
}
mmReturn = ::waveInStart(m_hRecord); //開始錄音
if(mmReturn==MMSYSERR_NOERROR ) recording=TRUE;
}
return TRUE;
}語音回放
相對錄音而言,播放就簡單多了,同樣用的一個CWinThread對象CAudioPlay來實現(xiàn),部分實現(xiàn)代碼:
LRESULT CAudioPlay::OnWriteSoundData(WPARAM wParam, LPARAM lParam)
{
//TRACE("CAudioPlay::OnWriteSoundData\n");
MMRESULT mmResult = FALSE;
char *p=NULL;
int length=(int) wParam;
if(Playing==FALSE)return FALSE;
if(length<=0)return FALSE;
WAVEHDR *lpHdr=new WAVEHDR;
if(!lpHdr)return FALSE;
p=new char [length];
if(!p){delete lpHdr;
return FALSE;}
ZeroMemory(lpHdr,sizeof(WAVEHDR));
ZeroMemory(p,length);
CopyMemory(p,(char*)lParam,length);
lpHdr->lpData=p;
lpHdr->dwBufferLength = length;
mmResult = ::waveOutPrepareHeader(m_hPlay, lpHdr, sizeof(WAVEHDR));
//為回放設(shè)備準備內(nèi)存塊
if(mmResult)
{
delete lpHdr;delete p;
return mmResult;
}
mmResult = ::waveOutWrite(m_hPlay, lpHdr, sizeof(WAVEHDR));//寫數(shù)據(jù)(放音)
if(mmResult){delete lpHdr;delete p;
return mmResult; }
m_Count++;
return MMSYSERR_NOERROR;
}視音頻的傳輸
視頻采集采用AVICap從視頻采集卡捕獲視頻圖像,得到的是位圖形式的視頻幀,然后用Divx編碼器進行壓縮,壓縮以后形成以幀為格式的Mpeg4流。通過Winsock實現(xiàn)壓縮后的視頻數(shù)據(jù)在局域網(wǎng)中的實時傳輸,接收完的數(shù)據(jù)交給Divx解碼器,以幀的格式解壓,最后實現(xiàn)視頻顯示。所以提出以幀為單位發(fā)送視頻數(shù)據(jù)流。為了在接收端能夠方便地提取出一幀,提出如表1所示的格式組建幀。完整的一幀由5個字段組成,各個字段的意義如下:幀開始標志:標志著一幀地開始,占用4個字節(jié)的空間;幀大?。罕硎菊麄€幀的大小,包括5個字段的大小,占用4個字節(jié)的空間;幀編號:表示幀的順序編號,占用4個字節(jié)的空間;幀類型:標志此幀是否是關(guān)鍵幀,占用1個字節(jié)的空間;幀數(shù)據(jù):存放壓縮后一幀的完整數(shù)據(jù)。
表1 視頻幀的格式
幀開始標志幀大小幀編號幀類型幀數(shù)據(jù)
0 4 8 12 13 2012
處理視頻傳輸如圖11所示。
圖11 視頻的傳輸
相對于視頻的傳輸,語音的傳輸就簡單得多了,在這里建立了兩個線程來處理,先來用一個語音錄制線程在一個客戶端錄制語音,再通過用G729a對語音進行編碼,然后傳輸?shù)搅硪豢蛻舳?,同樣用G729a對語音進行解碼,然后用一個語音回放線程將語音播放出來。
將視頻語音信息在客戶端顯示出來,如圖12所示。
圖12 語音視頻聊天
結(jié) 論
隨著通訊技術(shù)的普及和網(wǎng)絡(luò)的發(fā)展,社會上越來越重視信息交流的方便、及時和準確,借助網(wǎng)絡(luò)視頻通訊軟件實現(xiàn)“面對面”的網(wǎng)絡(luò)交流。由于信息量的無限擴大,交通工具的便捷,視頻技術(shù)的充分應用已經(jīng)成為現(xiàn)代通訊必不可少的一項技術(shù)運用?;诰钟蚓W(wǎng)的視頻聊天室系統(tǒng)可以跨越空間距離、靈活多樣的面對面的交互,適應現(xiàn)代社會的方便、快捷、高效、快節(jié)奏。
在編寫程序的過程中,我也遇到了很多的問題。通過老師的指點和查閱資料等得到了解決,并圓滿完成了整個程序的開發(fā)工作,同時積累了許多解決經(jīng)驗。這次的畢業(yè)設(shè)計達到了預期的目的,實現(xiàn)了文字聊天和語音視頻聊天。通過這次畢業(yè)設(shè)計,使我從理論到實踐邁出了堅實的一步。在學習理論、分析和組織程序結(jié)構(gòu)以及具體的實現(xiàn)等整個過程中,我體會到了編寫程序的酸、甜、苦、辣。要編寫出一個好的程序,必須要有縝密的思維,謹慎的作風和堅忍不拔的毅力。
參考文獻
[1] 謝希仁.計算機網(wǎng)絡(luò)[M].北京:電子工業(yè)出版社,2004。
[2] W. Richard Stevens.TCP/IP詳解[M].北京:機械工業(yè)出版社,2005。
[3] 張炯.Unix網(wǎng)絡(luò)編程[M].北京:清華大學出版社,2002。
[4] 求是科技,王正軍.Visual C++ 6.0從入門到精通[M].北京:人民郵電出版社,2006。
[5] 孫鑫,余安萍.VC++深入詳解[M].北京:電子工業(yè)出版社,2006。
[6] 陳堅,陳偉.Visual C++ 網(wǎng)絡(luò)高級編程[M].北京:人民郵電出版社,2001。
[7] 吳志軍.Visual C++視頻會議開發(fā)技術(shù)與實例[M].北京:人民郵電出版社,2006。
致 謝
整個論文工作是在王翔老師的悉心指導下完成的,王老師淵博的知識、嚴謹治學的態(tài)度、實干創(chuàng)新的精神、豐富的實踐經(jīng)驗和平易近人的為人給我留下了深刻的影響。在我做畢業(yè)論文過程中,他不斷的指導我學習方法,傳授我工作經(jīng)驗,使我受益匪淺,對順利完成本論文起到了極大的作用。在此向他表示我最衷心的感謝!論文初期,在王老師的幫助下論文才得以很好的展開,有了一個很好的開端!在編寫程序期間,王老師幫我排除了許多困難,解決了問題,也給了我許多的建議,使這個程序得以順利的完成。在論文的修改上,不管是論文格式、內(nèi)容還是圖表的處理等,王老師都細細幫助和指導。
在論文完成過程中,還得到了其他老師和許多同學的熱心幫助。程序的編程,調(diào)試程序以及最后的測試都是在他們熱心的幫助下完成的。在這里,我向所有關(guān)心和幫助我的人表示深深的謝意!
最后向在百忙之中評審本文的各位專家、老師表示衷心的感謝!