?? 用delphi開發視頻聊天室.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>用Delphi開發視頻聊天室</title>
</head>
<body>
<h1 align="center">用Delphi開發視頻聊天室</h1>
<p><br>
<strong>摘要:</strong>目前網上視頻聊天室、視頻會議軟件、可視IP電話軟件隨處可見,你是否想自己做一個玩玩?其實這類軟件無非是視頻加上網絡而建成的。如果熟悉視頻捕捉和網絡傳輸技術,根本就難不倒你。微軟為軟件開發人員提供了一個專門用于視頻捕捉的VFW SDK(Video for Windows SDK),用它實現視頻捕捉很簡單,至于網絡傳輸嘛,Delphi更是提供了N多種網絡組件,隨你用了。本文詳細介紹了如何利用Delphi中開發視頻聊天室,同時給出了兩個程序示例。 </p>
<p> </p>
<p> 關鍵詞:Delphi VFW 視頻 視頻會議 視頻聊天 Video for Windows<BR>
作者:徐長友(yousoft@sina.com)</p>
<h2>一、引言</h2>
我們知道視頻聊天室的關鍵技術在于采集視頻,并實時傳輸給聊天室在線的人。對于視頻的采集,這里采用微軟公司的關于數字視頻的一個軟件包VFW(Video for Windows)。相信很多人對它都很熟習,VFW能使應用程序通過數字化設備從傳統的模擬視頻源得到數字化的視頻剪輯,VFW的一個關鍵思想是播放時不需要專用硬件。為了解決數字視頻數據量大的問題,需要對數據進行壓縮,而VFW引進了AVI的文件標準。該標準未規定如何對視頻進行捕捉、壓縮及播放,僅規定視頻和音頻該如何存儲在硬盤上及在AVI文件中交替存儲視頻幀和與之相匹配的音頻數據。通過VFW,開發人員通過發送消息或設置屬性來捕捉、播放和編輯視頻剪輯。當用戶在安裝VFW時,安裝程序會自動地安裝配置視頻所需要的組件,如設備驅動程序、視頻壓縮程序等。VFW主要由6個模塊組成。VFW功能模塊:</p>
<p> AVICAP.DLL 包含執行視頻捕捉的函數,它給AVI文件的I/O處理和視頻、音頻設備驅動程序提供一個高級接口 </p>
<p> MSVIDEO.DLL 包含一套特殊的DrawDib函數,用來處理屏幕上的視頻操作 </p>
<p> MCIAVI.DRV 包括對VFW的MCI命令解釋器的驅動程序 </p>
<p> AVIFILE.DLL 包含由標準多媒體I/O(mmio)函數提供的更高的命令,用來訪問.AVI文件 </p>
<p> ICM 壓縮管理器,用于管理的視頻壓縮/解壓縮的編譯碼器(Codec) </p>
<p> ACM 音頻壓縮管理器,提供與ICM相似的服務,適用于波形音頻 </p>
<p>對于視頻的傳輸,我們使用UDP來傳,因為UDP傳輸速度快,TCP是面向連接的,建立連接時雙方需經過三次握手,數據傳輸可靠,FTP、telnet等就是基于TCP的,UDP是面向非連接的,發出信息不需對方確認,但這樣速度比TCP快,但有可能丟失數據,象SMTP、tftp等就是基于UDP的。另外UDP還支持廣播,UDP廣播兩種,一種是directed broadcast,比如你的網段是192.168.0.X,你就往192.168.0.255發就可以了。另一種是limited broadcast,廣播地址是255.255.255.255</p>
<h2> </h2>
<h2>二、視頻聊天室的開發步驟<br>
</h2>
<h3> 2.1 創建捕捉窗口,采集視頻</h3>
<p> 在進行視頻捕捉之前必需要先創建一個捕捉窗口,并應以此為基礎進行所有的捕捉及設置操作。捕捉窗口可用AVICap窗口類的“CapCreateCaptureWindow”函數來創建,其窗口風格可設置為WSCHILD和WS_VISIBLE參數。</p>
<p>有了捕捉窗口,我們就可以將視頻流和音頻流捕捉到一個AVI文件中;動態地同視頻和音頻輸入器件連接或斷開;用Overlay或Preview模式對輸入的視頻流進行實時顯示,設置捕捉速率,顯示控制視頻源、視頻格式及視頻壓縮的對話框,創建、保存或載入調色板,將圖像和相關的調色板拷貝到剪貼板,將捕捉的單幀圖像保存到BMP格式文件中。</p>
<h3> </h3>
<h3> 2.2 捕捉窗口和驅動程序的關聯</h3>
<p> 僅僅一個捕捉窗口是不能工作起來的,它必須要與一個設備相關聯才能取得視頻信號。用函數CapDriverConnect可使捕捉窗與其設備驅動程序相關聯。</p>
<h3> </h3>
<h3> 2.3設置視頻設備的屬性</h3>
<p> 通過設置TcaptureParms結構變量的各個成員變量,可以控制設備的采樣頻率、中斷采樣按鍵、狀態行為。設置好TcaptureParms結構變量后,可以用函CapCaptureSetSetup使設置生效。之后還可以用CapPreviewScale、CapPreviewRate設置預覽的比例與速度,也可以直接使用設備的默認值。</p>
<h3> </h3>
<h3> </h3>
<h3> 2.4打開預覽</h3>
<p> 利用函數CapOverlay可選擇是否采用疊加模式預覽,以使系統資源占用小,視頻顯示速度加快。然后用CapPreview啟動預覽功能,這時就可以在屏幕上看到來自攝像頭的圖像了。</p>
<h3> </h3>
<h3> </h3>
<h3> 2.5使用捕捉窗回調函數</h3>
<p> 前的四個步驟就可以建立一個基本的視頻捕捉程序了,如果想自己處理從設備捕捉到的視頻數據,則要使用捕捉窗回調函數來處理,比如一幀一幀地獲得視頻數據,也可以以流的方式獲得視頻數據等等。</p>
<h3> </h3>
<h3> </h3>
<h3> 2.6傳輸視頻流</h3>
<p> 使用回調函數可以取得第一幀的數據,我們使用網絡技術將數據發給其它機器,其它機品將接收的數據顯示出來。</p>
<h3> </h3>
<h3> 2.7接收視頻</h3>
<p> 接收UDP數據,同時將接收到的數據回顯出來,這樣就可以看到遠處傳來的視頻了。</p>
<h2>三、用Delphi編寫程序代碼</h2>
微軟的VFW SDK只有VC和VB版,并沒有Delphi版,不過在網上可以找到VFW.PAS文件,FW.PAS文件聲明了調用DLL中的各個函數和變量。(注:源代碼中提供了VFW.PAS文件)</p>
<p> 下面就以Delphi7開發一個網絡視頻聊天室,聊天室分兩個程序,一個是視頻采集程序并進行UDP廣播的視頻聊天室服務器,另一個是接收UDP廣播程序顯示傳來的視頻數據的視頻聊天室客戶端。</p>
<h3> </h3>
<h3> 3.1建立視頻聊天室服務器</h3>
<p> 3.1.1新建一個工程,命名為Project1.dpr,并把VFW.PAS加到USE中<br>
<img src="picture/image002.jpg" width="357" height="285"></p>
<p> 3.1.2在Form1上放置一個Tpanel控件,該控件用于顯示視頻。之后再放置兩個Tbutton控件,一個caption為“開始”,另一個Name為“停止”,放置一個UDP組件,這里用indy的IdUDPClient用來傳輸視頻,如圖示:<br>
<img src="picture/image004.jpg" width="283" height="301"></p>
<p>3.1.3定義全局變量</p>
<table width="100%" border="1" cellspacing="0" cellpadding="1">
<tr>
<td bgcolor="#FFFF99"><p> </p>
<p>CapWnd:THandle; //定義捕捉窗句柄</p>
<p> CapParms:TcaptureParms; //用于設置設備屬性的結構變量</p>
<p> BMPINFO:TBitmapInfo; //BMP圖像信息</p></td>
</tr>
</table>
<p><br>
</p>
<p>3.1.4編碼事件代碼</p>
<p>開始按鈕代碼:</p>
<table width="100%" border="1" cellspacing="0" cellpadding="1">
<tr>
<td bgcolor="#FFFF99"><p> </p>
<p> CapWnd := capCreateCaptureWindow('我的窗口',</p>
<p> WS_VISIBLE or WS_CHILD,//窗口樣式</p>
<p> 0, //X坐標</p>
<p> 0, //Y坐標</p>
<p> panel1.Width, //窗口寬</p>
<p> panel1.Height, //窗口高</p>
<p> panel1.handle, //窗口句柄</p>
<p> 0); //通常為0</p>
<p> if CapWnd = 0 then exit;</p>
<p> //定義幀捕捉回調函數</p>
<p> CapSetCallbackOnFrame(CapWnd,FrameCallBack);</p>
<p> CapParms.dwRequestMicroSecPerFrame:=1;</p>
<p> CapParms.fLimitEnabled:=FALSE;</p>
<p> CapParms.fCaptureAudio:=FALSE;</p>
<p> CapParms.fMCIControl:=FALSE;</p>
<p> CapParms.fYield:=TRUE;</p>
<p> CapParms.vKeyAbort:=VK_ESCAPE;</p>
<p> CapParms.fAbortLeftMouse:=False;</p>
<p> CapParms.fAbortRightMouse:=FALSE;</p>
<p> //讓設置生效</p>
<p> CapCaptureSetSetup(capWnd,@CapParms,sizeof(TCAPTUREPARMS));</p>
<p> CapPreviewRate(capWnd,33); //設置預覽視頻的頻率</p>
<p> CapCaptureSequenceNoFile(capWnd); //如果要捕捉視頻流,則要使用函數來指定不生成文件,不然會自動生成AVI文件</p>
<p> CapDriverConnect(CapWnd,0); //連接攝像頭設備,第二個參數是個序號,當系統中裝有多個顯示驅動程序時,其值分別依次為0到總個數如果有多個攝像頭,那么就是0->1->2</p>
<p> capGetVideoFormat(capWnd, @BMPINFO,sizeof(TBitmapInfo)); //取得視頻圖像數據頭</p>
<p> CapPreviewScale(capWnd,TRUE); //是否縮放</p>
<p> CapOverlay(capWnd,true); //指定是否使用疊加模式,true為使用,否則為false</p>
<p>CapPreview(capWnd,true);</p></td>
</tr>
</table>
<p><br>回調函數代碼:</p>
<p> </p>
<table width="100%" border="1" cellspacing="0" cellpadding="1">
<tr>
<td bgcolor="#FFFF99"><p> </p>
<p>var hd:Thandle;</p>
<p> jpg:TJpegImage;</p>
<p> memStream :TMemoryStream;</p>
<p> Bitmap:TBitmap;</p>
<p>begin</p>
<p> //將數據顯在Image,</p>
<p> Bitmap:=TBitmap.Create;</p>
<p> Bitmap.Width :=BMPINFO.bmiHeader.biWidth; // New size of Bitmap</p>
<p> Bitmap.Height:=BMPINFO.bmiHeader.biHeight;</p>
<p> hd:= DrawDibOpen;</p>
<p> DrawDibDraw(hd,Bitmap.canvas.handle,0,0,BMPINFO.BmiHeader.biwidth,</p>
<p>BMPINFO.bmiheader.biheight,@BMPINFO.bmiHeader,</p>
<p>lpVHdr^.lpData,0,0,BMPINFO.bmiHeader.biWidth,BMPINFO.bmiHeader.biheight,0);</p>
<p> DrawDibClose(hd);</p>
<p> //發送數據</p>
<p> memStream := TMemoryStream.Create;</p>
<p> jpg := TJpegImage.Create;</p>
<p> jpg.Assign(Bitmap);</p>
<p> jpg.CompressionQuality := 10; //jpg壓縮質量</p>
<p> jpg.JPEGNeeded;</p>
<p> jpg.Compress;</p>
<p> jpg.SaveToStream(memStream);</p>
<p> jpg.Free;</p>
<p> //因為UDP數據包有大小限制,這里如果超出部分,就沒有傳輸,完全可以發幾次發出去</p>
<p> Form1.IdUDPClient1.BroadcastEnabled:=true;//用廣播功能</p>
<p> if memStream.Size>Form1.IdUDPClient1.BufferSize then</p>
<p> //向192.168.0.X網段廣播,端口 9001</p>
<p> Form1.IdUDPClient1.SendBuffer('192.168.0.255',9001,memStream.Memory^,</p>
<p>Form1.IdUDPClient1.BufferSize)</p>
<p> else</p>
<p> Form1.IdUDPClient1.SendBuffer('192.168.0.255',9001,memStream.Memory^,memStream.Size);</p>
<p> memStream.Free;</p>
<p> Bitmap.Free;</p>
<p>End;</p></td>
</tr>
</table>
<p> </p>
<p>停止代碼:</p>
<table width="100%" border="1" cellspacing="0" cellpadding="1">
<tr>
<td bgcolor="#FFFF99"><p> </p>
<p>capCaptureAbort(CapWnd); //停止捕捉</p>
<p> capDriverDisconnect(CapWnd); //將捕捉窗同驅動器斷開</p></td>
</tr>
</table>
<p><br>
</p>
<p>完整的視頻聊天室服務器代碼:</p>
<table width="100%" border="1" cellspacing="0" cellpadding="1">
<tr>
<td bgcolor="#FFFF99"><p> </p>
<p>unit Unit1;</p>
<p> </p>
<p>interface</p>
<p> </p>
<p>uses</p>
<p> Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,</p>
<p> Dialogs, StdCtrls, ExtCtrls,VFW, IdBaseComponent, IdComponent, IdUDPBase,</p>
<p> IdUDPClient,jpeg;</p>
<p> </p>
<p>type</p>
<p> TForm1 = class(TForm)</p>
<p> Panel1: TPanel;</p>
<p> Button1: TButton;</p>
<p> Button2: TButton;</p>
<p> IdUDPClient1: TIdUDPClient;</p>
<p> procedure Button1Click(Sender: TObject);</p>
<p> procedure Button2Click(Sender: TObject);</p>
<p> private</p>
<p> { Private declarations }</p>
<p> public</p>
<p> { Public declarations }</p>
<p> end;</p>
<p> </p>
<p>var</p>
<p> Form1: TForm1;</p>
<p> CapWnd:THandle; //定義捕捉窗句柄</p>
<p> CapParms:TcaptureParms; //用于設置設備屬性的結構變量</p>
<p> BMPINFO:TBitmapInfo; //BMP圖像信息</p>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -