Window Mobile视频会议程序的开发 - enginetanmary的专栏 - CSDNBlog

来源:百度文库 编辑:神马文学网 时间:2024/04/28 18:13:25
Window Mobile视频会议程序的开发
适用平台
Pocket PC 2003 Phone Edition
Windows Mobile 2003/SE
Windows Mobile 5.0
开发工具
Microsoft Embedded Visual C++ 4.0
Microsoft Visual Studio 2005
及适用于各平台的SDK
摘要
本文介绍了通过使用一些开源的音频、视频编码以及实时流式传输协议库,编写适用于Windows Mobile的视频会议程序,实现桌面计算机和Windows Mobile移动设备在无线局域网上的文字、音频和视频通信,移动设备上视频会议的使用,可以给办公带来方便。
正文
编解码器的选择
这个视频会议程序中,我们选择视频画面的大小为176X144真彩色,使用桌面计算机连接的摄像头来获取,音频的品质为8kHz,8位量化,单声道。视频的捕获会依据画面的情况进行调整,在视频全速工作的时候,每秒钟的视频有30帧左右,加上音频的数据量。虽然音频和视频的品质都比较低,但是可以满足普通的视频会议的需求,直接传输原始数据将会占用比较多的网络带宽。所以,需要选择一个合适的编解码器来对音频、视频进行有效的压缩,在视频会议常用的一些标准中,我们有着比较多的选择。
1.视频编解码器的选择
视频编解码器来源于视频压缩标准,常用的有M-JPEG、MPEG系列和H.26X系列。MPEG系列标准由ISO/ IEC 制定,主要应用于视频存储、广播电视、网络传输的上的流媒体等。H.26X标准由ITU-T(国际电信联盟电信标准化部门)制定,包括H.261、H.263、H.264,主要应用于实时视频通信领域,如视频会议、可视电话等。通常情况下,H.26X标准侧重于视频和音频信息的数据压缩效率,以适合调整该系统在特定码率下传输,MPEG系列标准则倾向于控制质量而不是控制码率。综合考虑,这里选择算法复杂度较低,易于实现的H.263算法,实现在9.6Kbps到128Kbps之间的速率传输大小为176X144(QCIF),速度在1fps到15fps之间的画面。
2.音频编解码器的选择
视频会议中传输的音频主要是语音数据,针对语音数据的压缩,ITU-T(国际电信联盟电信标准化部门)也提出了一系列的标准,下表是对一些常见标准的一个简要比较。
名称
比特率(kbps)
复杂度
时延(ms)
编码器类型
G.722
64,56,48

30
子带编码
G.723.1
5.3,6.3

1.5
多脉冲
G726
16,24,32,40

0.125
ADPCM
G729A
8

10
CELP
这里使用G.726作为语音编解码器,选择传输速率为16kbps。原始音频为8kHz,8位,单声道,压缩比率为8。
网络传输协议的选择
视频会议进行的过程中,主要需要传输的是音频、视频这样的多媒体数据流.实时传输协议RTP(Real-time Transport Protocol)及实时传输控制协议RTCP(RTP Control Protocol)是IETF的AVT工作组发布的专门用于网络上传输多媒体数据流的一种传输协议,该协议可以实现在网络中的流媒体数据的单播和组播,同时为实时数据传输提供时序重构、帧丢失检测、数据安全等多种服务。这里使用UDP协议作为RTP协议的下层来传输数据。RTP是一种无连接的传输数据报文协议,它本身不为按顺序传送数据分组提供可靠的传送机制,也不提供流量控制或拥塞控制等服务,而是和RTCP协议一起来实现这些服务,RTCP是指接收方向数据发送方发送的控制报文,它提供网络传输QoS监测和拥塞控制、媒体间同步、识别信息、会议大小估计和控制信息量的调节等服务。在RTP会话期间,各会话成员周期性的发送RTCP控制包,利用这些控制信息可以灵活的改变数据传输速率,优化网络传输效率,更好的保证系统的实时性。
程序的编写
考虑到初步实现的有效性和开发工作的简化,这个程序只实现点对点视频会议的功能。使用TCP协议来进行会议控制,RTP协议进行数据传输。其中需要使用的H.263编解码使用开源的tmn/tmndec2.0库(来自http://www.h263l.com),G.726编解码使用OpenH323中关于G.726的部分程序(来自http:// www.openh323.org),RTP使用开源的Jrtplib库(来自http://research.edm.luc.ac.be/jori/jrtplib/jrtplib.html),版本为3.4.0。以上这些开源的包均要经过一定的修改才能够在EVC下编译、使用。
PC端程序
PC端程序需要实现的主要功能有:音频采集,视频捕获,相应的编解码传输,以及将接收到的文字信息进行显示,接收到的音频和视频画面解码播放。该程序在Windows 2000/XP平台上,使用VS.net2003中的VC++.net进行开发。Windows平台提供了一系列方便的API,比较容易的实现对音频、摄像头等设备的操作。使用WaveIn系列函数捕获音频,WaveOut系列函数进行音频播放,使用VFW(Video For Windows)进行视频捕获以及回放。同时要提供一个友好的界面。和界面相关的这里不再赘述。
1.使用VFW(Video For Windows)操作摄像头
VFW(Video For Windows)当中提供了一系列函数,来操作摄像头。使用这个需要包含头文件vfw.h,并且使用vfw32.lib库。基本步骤是,使用capCreateCaptureWindow来创建一个视频捕获窗口,用capSetCallbackOnVideoStream来设置捕获到新的视频数据的回调函数,capCaptureGetSetup和capCaptureSetSetup用来获得和设置捕获参数,使用capDriverConnect来连接设备。在设备和驱动都正常时,这些初始化工作将逐步完成,在这些操作成功完成后,这里使用capCaptureSequenceNoFile函数来开始视频捕获,有新的视频数据将不存入文件,而是存在回调函数的类型为videohdr_tag结构体的参数中,该结构体中的lpData和dwBytesUsed将分别指示这一帧数据的开始地址和长度。有了这些数据,就可以在程序中进行使用,显示在本地窗口或者压缩后发送出去。需要结束视频捕获,使用capCaptureAbort来停止,capDriverDisconnect来断开设备。
2.使用WaveIn/WaveOut系列函数来操作音频设备
这方面资料很多,这里简要叙述一下。需要包含mmsystem.h头文件,以及使用Winmm.lib库。
录音的操作:用waveInOpen来打开录音设备,该函数的WAVEFORMATEX类型的参数用来设置录音的质量,接着要为录音的音频数据准备缓冲,使用waveInPrepareHeader函数,其中的wavehdr_tag结构体类型的参数,其中的lpData和dwBufferlength将指示缓冲的地址和大小。做好准备工作之后,用WaveInStart开始录音。这里为了不断监视录音数据,可以开始一个线程循环监听(在CALL_BACKTHREAD模式的时候),在其中用GetMessage来获得消息,有新的音频数据到来将会有MM_WIM_DATA消息,在这个消息中取得音频数据,并且进行使用。停止录音的时候,用waveInUnprepareHeader来清除缓冲,waveInReset停止录音,waveInClose关闭录音设备。
播放声音的操作:用waveOutOpen打开音频输出设备,该函数的WAVEFORMATEX参数用来设置放音的质量,用waveOutPrepareHeader函数来给放音准备缓冲,在准备这个缓冲的时候将需要播放的数据安排好,具体就在这个函数的wavehdr_tag类型的参数中,进行播放时,用waveOutWrite函数,这个函数将引用waveOutPrepareHeader准备好的wavehdr_tag类型的参数,播放其对应的缓冲数据的内容。注意音频播放完成后将有WOM_DONE消息,在其中可以做释放缓冲的操作。停止播放时,用waveOutClose关闭音频输出设备。
3.使用H.263对视频画面压缩解压
Tmn/tmndec2.0库良好的封装为使用提供了极大的方便,InitH263Encoder和InitH263Decoder函数用来初始化编解码器,退出程序时用ExitH263Encoder和ExitH263Decoder来释放编解码器。
开始视频捕获之后,在视频捕获的回调函数中,使用CompressFrame函数进行压缩,注意使用这个函数之前需要设置好压缩参数,第一个类型为CParam的参数将指示需要压缩的数据所在的地址,还要设置好压缩的回调函数以将压缩后的数据写入到一个指定的缓冲当中。使用tmn库,定义一个函数,并且设置WriteByteFunction等于这个函数就可以设置这个回调函数。CompressFrame执行之后,将回调WriteByteFunction函数,在这个函数中将压缩后的数据写入需要的缓冲区,同时CompressFrame返回这一帧画面压缩后的数据的长度,以字节为单位。
在收到网络发送过来的视频数据后,用DecompressFrame进行解压,解压后的数据将以RGB数据类型存入这个函数所跟的参数指示的缓冲区中。读取这个缓冲区的数据进行远程视频的显示。
4.使用G.726对音频压缩解压
为了方便操作,作者将OpenH323中的G.726部分程序进行封装,提供了g726_Encode和g726_Decode两个函数,这两个函数的输入参数分别是压缩前后和解压前后存放数据的缓冲区的指针。在本地计算机有新的音频数据需要发送时,用g726_Encode进行压缩;从网络接收到新的音频数据时,用g726_Decode进行解压播放。
5.使用RTP进行数据传输
使用JrtpLib提供的RTPSession类,方便的调用RTP来进行传输,使用的时候用这个类来定义两个变量,RTP的传输将使用它们。
程序开始的时候要初始化RTP,初始化RTP数据发送的步骤:定义一个类型为RTPSessionParams的变量,用SetOwnTimestampUnit来设置时间戳,SetMaximumPacketSize来设置最大的RTP包大小,SetSourceTimeoutMultiplier来设置数据超时,定义一个类型为RTPUDPv4TransmissionParams的变量,用SetPortbase设置发送的基端口,注意这个必须是偶数,默认值为5000。初始化RTP数据接收步骤和这个相同。在设置好这些参数之后,使用RTPSession的Create方法来建立RTP数据接收和发送,这个方法所跟的参数正是RTPSessionParams和RTPUDPv4TransmissionParams这两个类型。
会议开始时要建立RTP会话,这里仅使用到RTP点对点的会话功能。在开始一个新的会话时,用RTPIPv4Address(intIP,PORT_DATA)来建立一个新的地址,其中intIP是由inet_addr通过IP地址字符串计算得来,使用AddDestination将这个地址增加到发送的地址列表中。结束一个会话的时候,用DeleteDestination来删除这个会话地址。
程序退出的时候,用RTPSession的Destroy来清理RTP所使用过的资源。
Windows Mobile端程序
Windows Mobile设备上安装的Windows CE操作系统提供了和桌面Windows很接近的WIN32 API,大多数WIN32 API的函数在Windows CE中都存在。目前这个初步的程序尚未编写视频捕获部分,这个程序中所要实现的功能,视频解码显示,录音和播放,H.263、G.726压缩和解压以及RTP会话,通过将VC++程序移植到EVC,都很方便、快捷的得以实现。由此也体会到微软公司产品,标准统一的平台以及开发环境,给软件开发工作带来的巨大方便。
作者使用的设备是Pocket PC 2003系统,上面没有对VFW的支持,所以在显示远程画面的时候,使用的GDI,将解压后的数据组合成一幅位图,再显示到窗口中。
解压显示部分代码如下:
retvalue=DecompressFrame(data,size,rgbdata,buffersize);

CBitmap bitmap;
bitmap.CreateBitmap(176,144,1,24,rgbdata);
CWnd* pWnd=GetDlgItem(IDC_REMOTEVIDEO);
pWnd->UpdateWindow();
CDC* pDC=pWnd->GetDC();
CDC bitmapDC;
bitmapDC.CreateCompatibleDC(pDC);
CBitmap* pOldBitmap = bitmapDC.SelectObject(&bitmap);
pDC->BitBlt(0,0,176,144,&bitmapDC,0,0,SRCCOPY);
bitmapDC.SelectObject(pOldBitmap);
bitmap.DeleteObject();
会议流程
以上部分只实现了基本的数据的采集、收发和使用,这个程序的另外一个重要部分就是会议的控制。由于作者时间和水平有限,这里临时使用了自己订立的一个协议,通过TCP来交换指令,实现对会议会话的流程控制。
会议的基本流程如下表所示:
呼叫方(PC/Windows Mobile)                   被呼叫方(PC/ Windows Mobile)
|                    1发出会议邀请(R)                        |
|--------------------------------------------------------------------------------------------> |
|                    2 接受邀请(Y)                            |
|<---------------------------------------------------------------------------------------------|
|                    3 确认接受(A)                           |
|--------------------------------------------------------------------------------------------> |
|                    4  RTP会话                                |
|<-------------------------------------------------------------------------------------------> |
|                    5 断开(D)                              |
|<---------------------------------      或者    -------------------------------------> |
|                    6 确认断开(C)                           |
|<---------------------------------      或者    -------------------------------------> |
|                    7 终止RTP会话                            |
会议过程中的数据收发
以上部分已经建立起一个可以进行会议数据收发的环境,提供好了相关的函数,在会议过程中,将使用这些函数来实现将本地数据发送到对方以及接收对方数据的功能。
RTP数据发送,使用SendPacket函数。
m_sessData.rtpSend.SendPacket(data, length, 0, false, 10UL);
RTP接收,这里使用的方法是使用它的OnRtpPacket函数,当RTP会话建立并且增加了目标地址后,从目标地址发送数据过来,将会调用这个函数,在这个函数里面取得装载数据并使用。
void RTPAppSession::OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime, const RTPAddress *senderaddress)
{
dlg->SendMessage(WM_CHAT_DATA_ARRIVED,(WPARAM)pack->GetPayloadData(),(LPARAM)(pack->GetPayloadLength()));
}
结论和展望
本文主要讲解了使用一些现有的库和WIN32 API,实现一个简单的PC和Windows Mobile相互通信的视频会议的过程。通过对这个程序的编写,极大的丰富了本人的知识,锻炼了动手能力。目前这个程序能够实现视频会议的基本功能,并且在PC和Windows Mobile上都可以稳定流畅的运行,但是距离实用的差距很大,是一种积极的学习和尝试。
后期作者将继续努力,使用SIP协议以及Windows Mobile 5.0的新功能等更加新的资源,完善和丰富这个程序的功能。
希望通过这篇文章和读者交流自己的经验和感受,促进学习,共同进步。
本人才疏学浅,经验有限,文中会存在不少错误,欢迎朋友们批评指正!
Window Mobile视频会议程序的开发 - enginetanmary的专栏 - CSDNBlog Window Mobile视频会议程序的开发 - enginetanmary的专栏 - CSDNBlog 什么才是软件开发的葵花宝典? - Matthew的专栏 - CSDNBlog 2007年web开发技术预言 - Lanneret_Lv的专栏 - CSDNBlog 关于搜索引擎及其开发 - xwjbs的专栏 - CSDNBlog liferay开发环境配置说明 - wahaha629的专栏 - CSDNBlog 典型的flex程序的编写步骤 - Booo.Lee 的专栏 - CSDNBlog 一个Dijkstra算法的完整Java程序实现,算法初学者必看! - brokencar的专栏 - CSDNBlog Asp.net程序性能优化的七个方面 - acefly的专栏 - CSDNBlog C armman的专栏 - CSDNBlog 使用程序自动调用ANSYS并运行命令流文件 - 王学福的专栏 - CSDNBlog Windows下程序向Linux下移植细节 - wenhm的专栏 - CSDNBlog 浅述如何为程序提供二次开发功能 - 1 (原创) - wisenowa的专栏 - CSDNBlog 将java程序运行为Windows服务 - dragonbbc的专栏 - CSDNBlog 学习 c#程序显示所选目录及其子目录内所有文件 - acefly的专栏 - CSDNBlog 当下10大最热门的网站开发技术 - tzsmin的专栏 - CSDNBlog 基于WEB应用开发的java程序员必备工具 - 辛佳雨的专栏 - CSDNBlog 手机网络应用客户端软件开发实践简介 - zjsjava的专栏 - CSDNBlog 软件工程文档模板----二、项目开发计划 - lihuaidong521的专栏 - CSDNBlog SD卡驱动开发随笔(1) - Professionaler(自由人)的专栏 - CSDNBlog Drupal专业开发指南 第1章 Drupal工作原理(1) - g089h515r806的专栏 - CSDNBlog Tapestry的介绍 - bfh365的专栏 - CSDNBlog CFileDialog的详解 - bhw1985的专栏 - CSDNBlog Xindice的FAQ - TKDD的专栏 - CSDNBlog