摘要:目前网上视频聊天软件、视频会议软件、可视IP电话软件随处可见,你是否想自己做一个玩玩?其实这类软件无非是视频加上网络而建成的。如果熟悉视频捕捉和网络传输技术,根本就难不倒你。微软为软件开发人员提供了一个专门用于视频捕捉的VFW SDK(Video for Windows SDK),用它实现视频捕捉很简单,至于网络传输嘛,Delphi更是提供了N多种网络组件,随你用了。本文详细介绍了如何利用Delphi中开发视频聊天软件,同时给出了两个程序示例。
  关键词:Delphi VFW 视频 视频会议 视频聊天 Video for Windows
  一、引言
  我们知道视频聊天软件的关键技术在于采集视频,并实时传输给聊天软件在线的人。对于视频的采集,这里采用微软公司的关于数字视频的一个软件包VFW (Video for Windows)。相信很多人对它都很熟习,VFW能使应用程序通过数字化设备从传统的模拟视频源得到数字化的视频剪辑,VFW的一个关键思想是播放时不需要专用硬件。为了解决数字视频数据量大的问题,需要对数据进行压缩,而VFW引进了AVI的文件标准。该标准未规定如何对视频进行捕捉、压缩及播放,仅规定视频和音频该如何存储在硬盘上及在AVI文件中交替存储视频帧和与之相匹配的音频数据。通过VFW,开发人员通过发送消息或设置属性来捕捉、播放和编辑视频剪辑。当用户在安装VFW时,安装程序会自动地安装配置视频所需要的组件,如设备驱动程序、视频压缩程序等。VFW主要由6个模块组成。VFW功能模块:
  AVICAP.DLL 包含执行视频捕捉的函数,它给AVI文件的I/O处理和视频、音频设备驱动程序提供一个高级接口
  MSVIDEO.DLL 包含一套特殊的DrawDib函数,用来处理屏幕上的视频操作
  MCIAVI.DRV 包括对VFW的MCI命令解释器的驱动程序
  AVIFILE.DLL 包含由标准多媒体I/O(mmio)函数提供的更高的命令,用来访问.AVI文件
  ICM 压缩管理器,用于管理的视频压缩/解压缩的编译码器(Codec)
  ACM 音频压缩管理器,提供与ICM相似的服务,适用于波形音频
  对于视频的传输,我们使用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
  二、视频聊天软件的开发步骤
  2.1 创建捕捉窗口,采集视频
  在进行视频捕捉之前必需要先创建一个捕捉窗口,并应以此为基础进行所有的捕捉及设置操作。捕捉窗口可用AVICap窗口类的"CapCreateCaptureWindow"函数来创建,其窗口风格可设置为WSCHILD和WS_VISIBLE参数。
  有了捕捉窗口,我们就可以将视频流和音频流捕捉到一个AVI文件中;动态地同视频和音频输入器件连接或断开;用Overlay或Preview模式对输入的视频流进行实时显示,设置捕捉速率,显示控制视频源、视频格式及视频压缩的对话框,创建、保存或载入调色板,将图像和相关的调色板拷贝到剪贴板,将捕捉的单帧图像保存到BMP格式文件中。
  2.2 捕捉窗口和驱动程序的关联
  仅仅一个捕捉窗口是不能工作起来的,它必须要与一个设备相关联才能取得视频信号。用函数CapDriverConnect可使捕捉窗与其设备驱动程序相关联。
  2.3设置视频设备的属性
  通过设置TcaptureParms结构变量的各个成员变量,可以控制设备的采样频率、中断采样按键、状态行为。设置好TcaptureParms结构变量后,可以用函CapCaptureSetSetup使设置生效。之后还可以用CapPreviewScale、CapPreviewRate设置预览的比例与速度,也可以直接使用设备的默认值。
  2.4打开预览
  利用函数CapOverlay可选择是否采用叠加模式预览,以使系统资源占用小,视频显示速度加快。然后用CapPreview启动预览功能,这时就可以在屏幕上看到来自摄像头的图像了。
  2.5使用捕捉窗回调函数
  前的四个步骤就可以建立一个基本的视频捕捉程序了,如果想自己处理从设备捕捉到的视频数据,则要使用捕捉窗回调函数来处理,比如一帧一帧地获得视频数据,也可以以流的方式获得视频数据等等。
  2.6传输视频流
  使用回调函数可以取得第一帧的数据,我们使用网络技术将数据发给其它机器,其它机品将接收的数据显示出来。
  2.7接收视频
  接收UDP数据,同时将接收到的数据回显出来,这样就可以看到远处传来的视频了。
  三、用Delphi编写程序代码
  微软的VFW SDK只有VC和VB版,并没有Delphi版,不过在网上可以找到VFW.PAS文件,FW.PAS文件声明了调用DLL中的各个函数和变量。(注:源代码中提供了VFW.PAS文件)
  下面就以Delphi7开发一个网络视频聊天软件,聊天软件分两个程序,一个是视频采集程序并进行UDP广播的视频聊天软件服务器,另一个是接收UDP广播程序显示传来的视频数据的视频聊天软件客户端。
  3.1建立视频聊天软件服务器
  3.1.1新建一个工程,命名为Project1.dpr,并把VFW.PAS加到USE中 
  3.1.2在Form1上放置一个Tpanel控件,该控件用于显示视频。之后再放置两个Tbutton控件,一个caption为"开始",另一个Name为"停止",放置一个UDP组件,这里用indy的IdUDPClient用来传输视频.
  3.1.3定义全局变量

CapWnd:THandle; //定义捕捉窗句柄
CapParms:TcaptureParms; //用于设置设备属性的结构变量
BMPINFO:TBitmapInfo; //BMP图像信息

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包限制,看到图像就不完整了)

http://blog.sina.com.cn/s/blog_56234909010103tr.html

用Delphi开发视频聊天软件的更多相关文章

  1. delphi视频聊天

    用Delphi开发视频聊天软件 一.引言 我们知道视频聊天软件的关键技术在于采集视频,并实时传输给聊天软件在线的人.对于视频的采集,这里采用微软公司的关于数字视频的一个软件包VFW(Video for ...

  2. 视频聊天插件:AnyChat使用攻略之iOS开发指南

    AnyChat使用攻略之iOS开发指南 这套攻略主要指导刚开始使用AnyChat SDK For iOS的同学,快速搭建SDK环境,和实现音视频开发流程. (需要工程案例文件可联系我们) 在iOS平台 ...

  3. 免费美女视频聊天,多人视频会议功能加强版本(Fms3和Flex开发(附源码))

    Flex,Fms3系列文章导航 Flex,Fms3相关文章索引 本篇是视频聊天,会议开发实例系列文章的第4篇,该系列所有文章链接如下: http://www.cnblogs.com/aierong/a ...

  4. 高仿QQ即时聊天软件开发系列之三登录窗口用户选择下拉框

    上一篇高仿QQ即时聊天软件开发系列之二登录窗口界面写了一个大概的布局和原理 这一篇详细说下拉框的实现原理 先上最终效果图 一开始其实只是想给下拉框加一个placeholder效果,让下拉框在未选择未输 ...

  5. 高仿QQ即时聊天软件开发系列之二登录窗口界面

    继上一篇高仿QQ即时聊天软件开发系列之一开端之后,开始做登录窗口 废话不多说,先看效果,只有界面 可能还有一些细节地方没有做,例如那个LOGO嘛,不要在意这些细节 GIF虽短,可是这做起来真难,好吧因 ...

  6. 小众Tox——大众的“去中心化”聊天软件

    ★Tox是什么 一个反窥探的开源项目:一种基于DHT(BitTorrent)技术的即时通讯协议:一个为安全而生的加密通讯系统 .美国棱镜计划曝光后,一个名为 irungentoo 的牛人于17天后的2 ...

  7. 视频聊天室可以用php制作吗?

    首先,告诉你单纯用php制作视频聊天室是实现不了的,需要配合其他技术手段一起操作,例如和FLASH配合,使用FLASH获取语音(FLASH可以获取访问端的设备,例如摄像头). PHP运行在服务器端,是 ...

  8. 在线教学、视频会议 Webus Fox(1)文本、语音、视频聊天及电子白板基本用法

    Webus Fox是基于网页的在线教学.视频会议软件,不用安装,直接使用.它提供文本.语音.视频聊天,文件共享.电子白板等功能. 1. 登录 访问 http://flash.webus.cn/#,用自 ...

  9. 工具武装的前端开发工程师 Mac 软件清单

    Awesome Mac  这个仓库主要是收集非常好用的Mac应用程序.软件以及工具,主要面向开发者和设计师.有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章<工具武装的前端开发工程 ...

随机推荐

  1. 行列式(determinant)的物理意义及性质

    1. 物理(几何)意义 detA=output areainput area 首选,矩阵代表的是线性变换(linear transformation).上式说明一个矩阵的行列式(detA)几何意义上, ...

  2. BZOJ 1864 三色二叉树 - 树型dp

    传送门 题目大意: 给一颗二叉树染色红绿蓝,父亲和儿子颜色必须不同,两个儿子颜色必须不同,问最多和最少能染多少个绿色的. 题目分析: 裸的树型dp:\(dp[u][col][type]\)表示u节点染 ...

  3. TextView中实现跑马灯的最简单方法

    几行代码实现跑马灯效果,效果如下: 因为很简单,所以就直接贴代码喽 <TextView android:id="@+id/item1_title_message" andro ...

  4. maven 依赖(依赖范围,聚合,继承等)

    目录: 1.什么是依赖? 2.依赖的管理:依赖的范围与传递,依赖的排除,依赖的原则(maven对依赖冲突的处理原则) 3.依赖的版本管理 4.继承与聚合 1.什么是依赖? 简单的讲,当jar包A需要j ...

  5. mingw-w64线程模型:posix vs win32(posix允许使用c++11的std:: thread,但要带一个winpthreads,可能需要额外dll)

    我正在安装 mingw-w64 on Windows,有两个选项: win32线程和posix线程. 我知道win32线程和pthreads之间的区别,但是我不明白这两个选项之间的区别. 我怀疑如果我 ...

  6. 获取全局上下文(getApplicationContext)_创建Shared Preference工具类_实现自动登录

    获取全局上下文(getApplicationContext)_创建Shared Preference工具类_实现自动登录 ===========================获取全局上下文(getA ...

  7. Android官方教程翻译(6)——添加ActionBar

    The action bar allows you to add buttons for the most important action items relating to the app's c ...

  8. dot net core 使用 usb

    原文:dot net core 使用 usb 本文告诉大家如何在 dot net core 使用 usb 目录 获得通知 读写 串口通信 LGPL 首先需要打开 Nuget 安装 CoreCompat ...

  9. WPF 中那些可跨线程访问的 DispatcherObject(WPF Free Threaded Dispatcher Object)

    原文 WPF 中那些可跨线程访问的 DispatcherObject(WPF Free Threaded Dispatcher Object) 众所周知的,WPF 中多数对象都继承自 Dispatch ...

  10. TabHost两种实现方式

    第一种:继承TabActivity,从TabActivity中用getTabHost()方法获取TabHost.只要定义具体Tab内容布局就行了. <?xml version="1.0 ...