3.1.4編碼事件代碼
開始按鈕代碼:
CapWnd := capCreateCaptureWindow('我的窗口', WS_VISIBLE or WS_CHILD,//窗口樣式 0, //X坐標 0, //Y坐標 panel1.Width, //窗口寬 panel1.Height, //窗口高 panel1.handle, //窗口句柄 0); //通常為0
if CapWnd = 0 then exit; //定義幀捕捉回調函數
CapSetCallbackOnFrame(CapWnd,FrameCallBack);
CapParms.dwRequestMicroSecPerFrame:=1;
CapParms.fLimitEnabled:=FALSE;
CapParms.fCaptureAudio:=FALSE;
CapParms.fMCIControl:=FALSE;
CapParms.fYIEld:=TRUE;
CapParms.vKeyAbort:=VK_ESCAPE;
CapParms.fAbortLeftMouse:=False;
CapParms.fAbortRightMouse:=FALSE; //讓設置生效
CapCaptureSetSetup(capWnd,@CapParms,sizeof(TCAPTUREPARMS));
CapPrevIEwRate(capWnd,33); //設置預覽視頻的頻率
CapCaptureSequenceNoFile(capWnd); //如果要捕捉視頻流,則要使用函數來指定不生成文件,不然會自動生成AVI文件 CapDriverConnect(CapWnd,0); //連接攝像頭設備,第二個參數是個序號,當系統中裝有多個顯示驅動程序時,其值分別依次為0到總個數如果有多個攝像頭,那麼就是0->1->2
capGetVideoFormat(capWnd, @BMPINFO,sizeof(TBitmapInfo)); //取得視頻圖像數據頭
CapPrevIEwScale(capWnd,TRUE); //是否縮放
CapOverlay(capWnd,true); //指定是否使用疊加模式,true為使用,否則為falseCapPrevIEw(capWnd,true);
回調函數代碼:
var hd:Thandle;
jpg:TJpegImage;
memStream :TMemoryStream;
Bitmap:TBitmap;
begin //將數據顯在Image,
Bitmap:=TBitmap.Create;
Bitmap.Width :=BMPINFO.bmiHeader.biWidth;
// New size of Bitmap
Bitmap.Height:=BMPINFO.bmiHeader.biHeight;
hd:= DrawDibOpen; DrawDibDraw(hd,Bitmap.canvas.handle,0,0,_
BMPINFO.BmiHeader.biwidth,BMPINFO.bmiheader.biheight,_
@BMPINFO.bmiHeader,lpVHdr^.lpData,0,0,BMPINFO.bmiHeader.biWidth,_
BMPINFO.bmiHeader.biheight,0);
DrawDibClose(hd); //發送數據
memStream := TMemoryStream.Create;
jpg := TJpegImage.Create;
jpg.Assign(Bitmap);
jpg.CompressionQuality := 10; //jpg壓縮質量
jpg.JPEGNeeded;
jpg.Compress;
jpg.SaveToStream(memStream);
jpg.Free; //因為UDP數據包有大小限制,這裡如果超出部分,就沒有傳輸,完全可以發幾次發出去
Form1.IdUDPClIEnt1.BroadcastEnabled:=true;//用廣播功能
if memStream.Size>Form1.IdUDPClIEnt1.BufferSize then
//向192.168.0.X網段廣播,端口 9001
Form1.IdUDPClient1.SendBuffer('192.168.0.255',9001,memStream.Memory^,Form1.IdUDPClient1.BufferSize) else Form1.IdUDPClIEnt1.SendBuffer('192.168.0.255',9001,memStream.Memory^,memStream.Size);
memStream.Free;
Bitmap.Free;
End;
停止代碼:
capCaptureAbort(CapWnd); //停止捕捉 capDriverDisconnect(CapWnd); //將捕捉窗同驅動器斷開
完整的視頻聊天軟件服務器代碼:
unit Unit1;
interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,VFW, IDBaseComponent, IdComponent, IdUDPBase, IdUDPClIEnt,jpeg;type TForm1 = class(TForm) Panel1: TPanel;
Button1: TButton;
Button2: TButton;
IdUDPClient1: TIdUDPClIEnt;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
end;
var Form1: TForm1;
CapWnd:THandle; //定義捕捉窗句柄
CapParms:TcaptureParms; //用於設置設備屬性的結構變量
BMPINFO:TBitmapInfo; //BMP圖像信息
implementation{$R *.dfm}
function FrameCallBack(hWnd: HWND; lpVHdr: PVIDEOHDR): LongInt;stdcall;
var hd:Thandle;
jpg:TJpegImage;
memStream :TMemoryStream;
Bitmap:TBitmap;
begin //將數據顯在Image,
Bitmap:=TBitmap.Create;
Bitmap.Width :=BMPINFO.bmiHeader.biWidth;
// New size of Bitmap
Bitmap.Height:=BMPINFO.bmiHeader.biHeight;
hd:= DrawDibOpen;
DrawDibDraw(hd,Bitmap.canvas.handle,0,0,BMPINFO.BmiHeader.biwidth,BMPINFO._
bmiheader.biheight,@BMPINFO.bmiHeader,_
lpVHdr^.lpData,0,0,BMPINFO.bmiHeader.biWidth,BMPINFO.bmiHeader.biheight,0);
DrawDibClose(hd);
//發送數據
memStream := TMemoryStream.Create;
jpg := TJpegImage.Create; jpg.Assign(Bitmap);
jpg.CompressionQuality := 10;
//jpg壓縮質量
jpg.JPEGNeeded;
jpg.Compress;
jpg.SaveToStream(memStream);
jpg.Free;
//因為UDP數據包有大小限制,這裡如果超出部分,就沒有傳輸,完全可以發幾次發出去
Form1.IdUDPClIEnt1.BroadcastEnabled:=true;//用廣播功能
if memStream.Size>Form1.IdUDPClIEnt1.BufferSize then
//向192.168.0.X網段廣播,端口 9001
Form1.IdUDPClient1.SendBuffer('192.168.0.255',9001,memStream.Memory^,Form1.IdUDPClIEnt1.BufferSize)
else
Form1.IdUDPClIEnt1.SendBuffer('192.168.0.255',9001,memStream.Memory^,memStream.Size);
memStream.Free;
Bitmap.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
CapWnd := capCreateCaptureWindow('我的窗口', WS_VISIBLE or WS_CHILD,//窗口樣式
0, //X坐標
0, //Y坐標
panel1.Width, //窗口寬
panel1.Height, //窗口高
panel1.handle, //窗口句柄
0); //通常為0
if CapWnd = 0 then exit; //定義幀捕捉回調函數
CapSetCallbackOnFrame(CapWnd,FrameCallBack);
CapParms.dwRequestMicroSecPerFrame:=1;
CapParms.fLimitEnabled:=FALSE;
CapParms.fCaptureAudio:=FALSE;
CapParms.fMCIControl:=FALSE;
CapParms.fYIEld:=TRUE;
CapParms.vKeyAbort:=VK_ESCAPE;
CapParms.fAbortLeftMouse:=False;
CapParms.fAbortRightMouse:=FALSE; //讓設置生效
CapCaptureSetSetup(capWnd,@CapParms,sizeof(TCAPTUREPARMS));
CapPrevIEwRate(capWnd,33); //設置預覽視頻的頻率
CapCaptureSequenceNoFile(capWnd); //如果要捕捉視頻流,則要使用函數來指定不生成文件,不然會自動生成AVI文件
CapDriverConnect(CapWnd,0); //連接攝像頭設備,第二個參數是個序號,當系統中裝有多個顯示驅動程序時,其值分別依次為0到總個數如果有多個攝像頭,那麼就是0->1->2 capGetVideoFormat(capWnd, @BMPINFO,sizeof(TBitmapInfo)); //取得視頻圖像數據頭
CapPrevIEwScale(capWnd,TRUE); //是否縮放
CapOverlay(capWnd,true); //指定是否使用疊加模式,true為使用,否則為false CapPrevIEw(capWnd,true);end;procedure TForm1.Button2Click(Sender: TObject);
begin capCaptureAbort(CapWnd); //停止捕捉
capDriverDisconnect(CapWnd); //將捕捉窗同驅動器斷開
end;
end.
3.2建立視頻聊天軟件客戶端
3.2.1新建一個工程,命名為Project2.dpr
3.2.2在程序窗口Form2上放置一個image控件,該控件用於接收的圖像內容,再放置一個Tbutton控件,caption為"接收",,放置一個UDPServer組件,這裡用indy的IdUDPServer用來接收網絡視頻,如圖示:
接收按鈕代碼:
IdUDPServer1.DefaultPort:=9001; //接收端口 IdUDPServer1.Active:=true; //啟用
IdUDPServer1的UDPRead事件代碼:
var jpg:TJpegImage;begin try jpg := TJpegImage.Create; jpg.LoadFromStream(Adata); Image1.Picture.Bitmap.Assign(jpg); jpg.Free; exceptend;end;
視頻的傳輸是壓縮成JPG進行傳輸的,服務器端和接收端都用到了jpeg單元,所以use中都要加入jpeg。
完整的視頻聊天軟件客戶端代碼:
unit Unit2;
interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, IDBaseComponent, IdComponent, IdUDPBase, IdUDPServer, ExtCtrls,jpeg,IdSocketHandle;
type TForm1 = class(TForm) Image1: TImage;
IdUDPServer1: TIdUDPServer;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure IdUDPServer1UDPRead(Sender: TObject;
AData: TStream; ABinding: TIdSocketHandle);
private { Private declarations }
public
{
Public declarations
}
end;
var Form1: TForm1;
implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
IdUDPServer1.DefaultPort:=9001; //接收端口
IdUDPServer1.Active:=true; //啟用
end;
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject;AData: TStream; ABinding: TIdSocketHandle);
var jpg:TJpegImage;
begin
try
jpg := TJpegImage.Create;
jpg.LoadFromStream(Adata);
Image1.Picture.Bitmap.Assign(jpg);
jpg.Free;
except
end;
end;
end.
好了,到這裡程序代碼也就寫完了。在機上運行視頻聊天軟件服務器程序,點開始就開始進行視頻的傳輸了,在網絡上(網段為192.168.0.X,根據你的網絡設置IP地址,我這用的局域網測試)的任何一台機上運行視頻聊天軟件客戶端點接收都能接收到視頻了。
如果要接收的視頻內容清晰點,可以設置jpg.CompressionQuality:=10;(這個值可以是從1至100,數值越大,圖像越清晰,當然傳輸的速度會越慢了,圖像越清晰,數據包就會越大,如果超出了UDP包限制,看到圖像就不完整了)
視頻聊天軟件服務器
聊天軟件客戶端
四、結束語
在這裡,我把自己的一些經驗和代碼拿出來與大家一起分享,請高手不要扔雞蛋啊,我真的是花了不少力氣的!看了這篇文章後,相信你也可以自己動手做一個網絡視頻聊天軟件,也可以做個類似MSN、QQ、E話通一樣的視頻聊天軟件,有了網絡視頻就可以在千裡之外和家人進行可視通訊了。上面的示例程序還有很多地方需要改進的,比如視頻的壓縮可以用其它視頻壓縮編碼器進行壓縮,這裡只講了傳輸圖像,並沒有聲音,再改一下就才能傳輸音視頻了,有興趣的朋友不妨自己動手去試一試。