用Delphi开发视频聊天软件

一、引言

  我们知道视频聊天软件的关键技术在于采集视频,并实时传输给聊天软件在线的人。对于视频的采集,这里采用微软公司的关于数字视频的一个软件包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包限制,看到图像就不完整了)

  视频聊天软件服务器

  聊天软件客户端

  四、结束语

  在这里,我把自己的一些经验和代码拿出来与大家一起分享,请高手不要扔鸡蛋啊,我真的是花了不少力气的!看了这篇文章后,相信你也可以自己动手做一个网络视频聊天软件,也可以做个类似MSN、QQ、E话通一样的视频聊天软件,有了网络视频就可以在千里之外和家人进行可视通讯了。上面的示例程序还有很多地方需要改进的,比如视频的压缩可以用其它视频压缩编码器进行压缩,这里只讲了传输图像,并没有声音,再改一下就才能传输音视频了,有兴趣的朋友不妨自己动手去试一试。

delphi视频聊天的更多相关文章

  1. 用Delphi开发视频聊天软件

    摘要:目前网上视频聊天软件.视频会议软件.可视IP电话软件随处可见,你是否想自己做一个玩玩?其实这类软件无非是视频加上网络而建成的.如果熟悉视频捕捉和网络传输技术,根本就难不倒你.微软为软件开发人员提 ...

  2. 使用WebRTC搭建前端视频聊天室——点对点通信篇

    WebRTC给我们带来了浏览器中的视频.音频聊天体验.但个人认为,它最实用的特性莫过于DataChannel——在浏览器之间建立一个点对点的数据通道.在DataChannel之前,浏览器到浏览器的数据 ...

  3. 使用WebRTC搭建前端视频聊天室——信令篇

    博客原文地址 建议看这篇之前先看一下使用WebRTC搭建前端视频聊天室——入门篇 如果需要搭建实例的话可以参照SkyRTC-demo:github地址 其中使用了两个库:SkyRTC(github地址 ...

  4. 使用WebRTC搭建前端视频聊天室——入门篇

    http://segmentfault.com/a/1190000000436544 什么是WebRTC? 众所周知,浏览器本身不支持相互之间直接建立信道进行通信,都是通过服务器进行中转.比如现在有两 ...

  5. 循序渐进做项目系列(4)迷你QQ篇(2)——视频聊天!(附源码)

    一·效果展示 源码派送:MiniQQ1.1 文字聊天的实现参见:循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天 二·服务端设计 对于实现视频聊天而言,服务端最核心的工作就是要构造多媒 ...

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

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

  7. WebRTC实现网页版多人视频聊天室

    因为产品中要加入网页中网络会议的功能,这几天都在倒腾 WebRTC,现在分享下工作成果. 话说 WebRTC Real Time Communication 简称 RTC,是谷歌若干年前收购的一项技术 ...

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

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

  9. 如何实现:录制视频聊天的全过程? 【低调赠送:QQ高仿版GG 4.3 最新源码】

    前段时间做个项目,客户需要将视频对话的整个过程录制下来,这样,以后就可以随时观看.想来录制整个视频聊天的过程这样的功能应该是个比较常见的需求,比如,基于网络语音视频的1:1的英语口语辅导,如果能将辅导 ...

随机推荐

  1. App Store 审核指南(最新)

    简介 App 正在改变世界,丰富人们的生活,并为像您一样的开发者提供前所未有的创新机会.因此,App Store 已成长为一个激动人心且充满活力的生态系统,正为数百万的开发者和超过十亿的用户提供服务. ...

  2. python 集合互相转换

    #-*-coding:utf-8-*- #1.字典 dict = {'name': 'Zara', 'age': 7, 'class': 'First'} #字典转为字符串,返回:<type ' ...

  3. vim display line number

    cd /etc/vim sudo chmod 777 vimrc add :ser number to vimrc, then save and quit

  4. [译]在IB中实现自动布局

    有关自动布局的其他文章: Autolayout Visual format language for autolayout Creating individual constraints 可怜的界面编 ...

  5. SuperIndicator 一个专用打造轮播的类库

    Github地址:https://github.com/hejunlin2013/SuperIndicator,欢迎fork,star.著名Android-Universal-Image-Loader ...

  6. Android JNI&NDK编程小结及建议

    前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...

  7. Mac Pro 系统自带python路径

    /usr/local/Frameworks/Python.framework/Versions/2.7/bin

  8. Zookeeper demo增删改查

    Zookeeper 的增删改查demo代码 public class SimpleZkClient { private static final String connectString = &quo ...

  9. GCC + GDB 调试方法

    首先编译程序  多加一个 -g c++ test.cpp -o a -Wall -g 执行时使用 gdb a 此时输入 l 显示所有的代码 l 输入b 加入断点到某一行(break) b 108 运行 ...

  10. 【音乐App】—— Vue-music 项目学习笔记:歌手详情页开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 歌曲列表 歌曲播放 一.子 ...