﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Dark Angle-随笔分类-Audio&amp;Video</title><link>http://www.cppblog.com/niewenlong/category/5216.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 13:11:37 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 13:11:37 GMT</pubDate><ttl>60</ttl><item><title>几种开源SIP协议栈对比 </title><link>http://www.cppblog.com/niewenlong/archive/2007/09/24/32792.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 24 Sep 2007 09:08:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/09/24/32792.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/32792.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/09/24/32792.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/32792.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/32792.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;随着VoIP和NGN技术的发展，H.323时代即将过渡到SIP时代，在H.323的开源协议栈中，Openh323占统治地位，它把一个复杂而又先进的H.323协议栈展现在普通程序员的眼前，为H.323普及立下了汗马功劳。而然当在SIP时代，则出现了群雄割据的状况，SIP相对于H.323简单，灵活，于是各种协议栈层出不穷，下面将详细对比最具有代表性的5个开源项目：OPAL,VOCAL,sipX,ReSIProcate,oSIP
<p>&#160;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;OPAL是Open&nbsp;Phone&nbsp;Abstraction&nbsp;Library，是Openh323的下一个版本，它仍然使用了Openh323的体系结构，并在其基础上进行扩展，同时实现了SIP,H.323，但在音频和视频的编码和传输部分有较大改动。OPAL初衷设计是包含任何电话通信协议，所以其底层进行了高度的抽象化，所以也能够很容易的支持MGCP,PSTN和将来会出现的协议。不过由于Openh323的最后一个版本还在开发中，所以原本6月发布的OPAL也被推迟，现有的OPAL还非常不完善，BUG也非常多，不过相信以Openh323的开发班底，一定能让OPAL十分优秀。 </p>
<p>CVS&nbsp;:&nbsp;:pserver:anonymous@cvs.sourceforge.net:/cvsroot/openh323/opal <br>Language&nbsp;:&nbsp;C++ <br>VxWorks&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Win32&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Linux&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3261&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;2327&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3264&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3263&nbsp;:&nbsp;No&nbsp; <br>Supports&nbsp;RFC&nbsp;3515&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3262&nbsp;:&nbsp;No&nbsp; <br>Supports&nbsp;RFC&nbsp;3311&nbsp;:&nbsp;No&nbsp; <br>TCP&nbsp;:&nbsp;Yes&nbsp; <br>UDP&nbsp;:&nbsp;Yes&nbsp; <br>SIZE&nbsp;:&nbsp;&nbsp;8MB <br>License&nbsp;:&nbsp;MPL <br>Document&nbsp;:&nbsp;None <br>Samples&nbsp;:&nbsp;UA,GK </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;VOCAL是vovida.org开发的SIP系统，VOCAL应该是目前功能最完善，使用者最多的开源SIP协议栈了.它不只包括了协议栈，还包括了h323与sip转换网关，对SIP的各种Server的功能支持也非常完善.不过很可惜，不支持windows平台，而且自从vovida被CISCO收购以后就停止了开发，最后的版本是2003年4月的1.5.0。 <br>CVS&nbsp;:&nbsp;:pserver:anonymous@cvs.vovida.org:/cvsroot/vocal <br>Language&nbsp;:&nbsp;C++ <br>VxWorks&nbsp;port&nbsp;:&nbsp;No&nbsp; <br>Win32&nbsp;port&nbsp;:&nbsp;Partial&nbsp; <br>Linux&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3261&nbsp;:&nbsp;Partial&nbsp; <br>Supports&nbsp;RFC&nbsp;2327&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3264&nbsp;:&nbsp; <br>Supports&nbsp;RFC&nbsp;3263&nbsp;:&nbsp; <br>Supports&nbsp;RFC&nbsp;3515&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3262&nbsp;:&nbsp; <br>Supports&nbsp;RFC&nbsp;3311&nbsp;:&nbsp; <br>TCP&nbsp;:&nbsp;Yes&nbsp; <br>UDP&nbsp;:&nbsp;Yes&nbsp; <br>SIZE&nbsp;:&nbsp;6MB <br>License:&nbsp;Vovida&nbsp;software&nbsp;licencse <br>Document&nbsp;:&nbsp;Few <br>Samples&nbsp;:&nbsp;UA,GK,GW </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;sipX是一个SIP系统，由SIPFoundry开发。sipX是从reSIProcate分离出来的，sipX除了包括SIP&nbsp;stack外，还包括了sipXphone,sipXproxy,sipXregistry等等...,由它们构成了完整的SIP系统，而且sipx还支持嵌入式系统，各个模块可以按需取舍。不过可惜是几乎没有任何开发文档。 <br>SVN&nbsp;:&nbsp;http://scm.sipfoundry.org/viewsvn/ <br>Language&nbsp;:&nbsp;C++ <br>VxWorks&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Win32&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Linux&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3261&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;2327&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3264&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3263&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3515&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3262&nbsp;:&nbsp;No&nbsp; <br>Supports&nbsp;RFC&nbsp;3311&nbsp;:&nbsp;No&nbsp; <br>TCP&nbsp;:&nbsp;Yes&nbsp; <br>UDP&nbsp;:&nbsp;Yes&nbsp; <br>SIZE&nbsp;:&nbsp;&lt;4&nbsp;Mb&nbsp; <br>License&nbsp;:&nbsp;LGPL&nbsp; <br>Document&nbsp;:&nbsp;None <br>Samples&nbsp;:&nbsp;UA,GK,GW </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;ReSIProcate同样也是由SIPFoundry开发，ReSIProcate最开始起源于Vocal,由于Vocal开始只支持rfc3254，为了支持最新的rfc3261,ReSIProcate诞生了，但现在，ReSIProcate已经成为一个独立SIP协议栈了，它十分稳定，并且很多商业程序都在使用。 <br>SVN&nbsp;:&nbsp;http://scm.sipfoundry.org/viewsvn/resiprocate/main/sip/ <br>Language&nbsp;:&nbsp;C++ <br>VxWorks&nbsp;port&nbsp;:&nbsp;No&nbsp; <br>Win32&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Linux&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3261&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;2327&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3264&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3263&nbsp;:&nbsp;Partial&nbsp; <br>Supports&nbsp;RFC&nbsp;3515&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3262&nbsp;:&nbsp;No&nbsp; <br>Supports&nbsp;RFC&nbsp;3311&nbsp;:&nbsp;No&nbsp; <br>TCP&nbsp;:&nbsp;Yes&nbsp; <br>UDP&nbsp;:&nbsp;Yes&nbsp; <br>SIZE&nbsp;:&nbsp;&lt;&nbsp;2.5&nbsp;Mb&nbsp; <br>License&nbsp;:&nbsp;Vovida&nbsp; <br>Document&nbsp;:&nbsp;Few <br>Samples&nbsp;:&nbsp;None </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;oSIP的开发开始于2000年7月，第一个版本在2001年5月发布，到现在已经发展到2.0.9了。它采用ANSI&nbsp;C编写，而且结构简单小巧，所以速度特别快，它并不提供高层的SIP会话控制API,它主要提供一些解析SIP/SDP消息的API和事务处理的状态机，oSIP的作者还开发了基于oSIP的UA&nbsp;lib:exosip和proxy&nbsp;server&nbsp;lib:partysip. <br>CVS&nbsp;:&nbsp;:ext:anoncvs@savannah.gnu.org:/cvsroot/osip <br>Language&nbsp;:&nbsp;C <br>VxWorks&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Win32&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Linux&nbsp;port&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3261&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;2327&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3264&nbsp;:&nbsp;Yes&nbsp; <br>Supports&nbsp;RFC&nbsp;3263&nbsp;:&nbsp;Yes <br>Supports&nbsp;RFC&nbsp;3515&nbsp;:&nbsp;No&nbsp; <br>Supports&nbsp;RFC&nbsp;3262&nbsp;:&nbsp;No&nbsp; <br>Supports&nbsp;RFC&nbsp;3311&nbsp;:&nbsp;Yes&nbsp; <br>TCP&nbsp;:&nbsp;Yes <br>UDP&nbsp;:&nbsp;Yes <br>SIZE&nbsp;:&nbsp;400kb&nbsp; <br>License&nbsp;:&nbsp;LGPL <br>Samples&nbsp;:&nbsp;UA,GK </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;综合上述评测，可以看出5种SIP协议栈各有千秋，OPAL有发展潜力，VOCAL比较完善，sipX兼容性好，ReSIProcate教稳定，oSIP小巧而快速。所以要根据应用的不同选择恰当的协议栈进行研究开发。</p>
<img src ="http://www.cppblog.com/niewenlong/aggbug/32792.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-09-24 17:08 <a href="http://www.cppblog.com/niewenlong/archive/2007/09/24/32792.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于DirectShow的MPEG-4视频传输系统的研究与实现</title><link>http://www.cppblog.com/niewenlong/archive/2007/09/24/32782.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 24 Sep 2007 06:47:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/09/24/32782.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/32782.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/09/24/32782.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/32782.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/32782.html</trackback:ping><description><![CDATA[本文简单介绍了DirectShow技术，研究了利用DirectShow实现视频采集、压缩和网络传输技术。并利用第三方提供的编解码器实现了MPEG-4视频数据的网络传输系统，在该系统中利用RTP协议进行视频数据传输，同时实现了远端帧率的控制。<br><strong>关键词 </strong>视频; 采集; 压缩; DirectShow; MPEG-4,RTP<br><br><strong>1 引言</strong><br>&nbsp;&nbsp;&nbsp; 近年来，随着国民经济的发展，社会各个部门对于视频监视系统的需求越来越多。但目前的很多监视系统都跟具体的硬件相关，必须要具体的采集卡的支持才能实现。所以有必要开发一种具有通用性的视频监视系统，用普通的摄像头就能实现视频的采集。<br>&nbsp;&nbsp;&nbsp; 基于DirectShow的开发能很灵活地控制音视频的效果，所以选择DirectShow这种可扩展性好的技术做开发对以后的应用升级很有帮助。此外， 为了实现流媒体传输控制的策略，流媒体的传输和回放也是应解决的问题之一。由Microsoft提供的DirectShow技术基于组件对象模型技术，支 持宽松的格式变化，提供高品质的多媒体流回放。利用它可以在普通微机中实现流媒体的客户端处理，并可以提高系统的通用性和可扩展性。<br>&nbsp;&nbsp;&nbsp; 对于视频数据的传输，压缩率是一个必须考虑到的因素。MPEG-4是由ISO和IEC的MPEG组制定的一个关于活动图像和声音的编码国际标准。它在基于 内容的交互性、压缩率、通用访问能力等方面提供了一系列新的或改进的功能。MPEG-4视频在提供较好的图像质量的同时拥有较高的压缩率，适合于作为传输 的图像压缩标准。 <br><br><strong>2&nbsp; 相关技术<br><br>2.1 DirectShow技术简介<br></strong>&nbsp;&nbsp;&nbsp; &nbsp;DirectShow是Microsoft为开发高性能多媒体应用而开发的底层应用程序接口（API）,它是DirectX家族的核心成员之一。 DirectShow自身是通过一种系统内置的或程序员开发的过滤器（Filter）来控制和处理多媒体数据的体系结构。该体系结构定义了如何处理和控制 过滤器内部及相互之间的多媒体数据流。每个过滤器都有输入或输出针（Pin）, 或两者都有。<br>&nbsp;&nbsp;&nbsp; 过滤器（Filter）是DirectShow的基本组成部分，是Filter Graph(过滤器图)中最小的功能模块，DirectShow将多媒体数据的处理分离成不同的步骤，这些不同的步骤由相应的Filter去处理。这样我 们可以把不同的过滤器搭配在一起达到我们要求的来处理多媒体数据。过滤器根据实现功能的不同大致可分为3类：<br>（1）&nbsp;源过滤器（Source Filters）。源过滤器负责得到原始媒体数据。这些媒体数据的来源包括本地硬盘或网络上的媒体文件、各种采集卡等。<br>（2）&nbsp;转换过滤器（Transform Filters）。转换过滤器的任务是处理从其他过滤器中接收的数据，经过一定的处理后再传递给下一个过滤器。编解码器就是典型的转换过滤器。<br>（3）&nbsp;表现过滤器（Rendering Filters）。表现过滤器对接收到的数据进行最后的处理。它做的工作有：把媒体数据保存为文件、将数据发送到网络、显示视频、回放音频等[1]。<br>&nbsp;&nbsp;&nbsp; 在DirectShow 系统之上是应用程序(Application) 。应用程序要按照程序所要实现的功能建立起相应的Filter Graph ,然后借助于Filter Graph Manager 来控制整个数据的处理过程。DirectShow 能在Filter Graph 运行的时候接收到各种事件,并通过消息的方式发送到应用程序。这样就实现了应用程序与DirectShow 系统之间的交互。<br><strong>2.2 RTP/RTCP协议介绍<br></strong>&nbsp;&nbsp;&nbsp; 实时传输协议RTP(Realtime Transport Protocol)是针对Internet 上多媒体数据流的一个传输协议，1996 年由IETF( Internet 工程任务组) 的AVT小组作为RFC1889 发布AVT小组后来对该文档进行了不断改进，于2003年7月提出了代替RFC1889的RFC3550。RTP充分体现了应用层分帧这一现代通信协议的 设计思想，允许其用户了解、调整甚至制定连续媒体的打包方案，该协议被广泛用于VoIP、视频等实时媒体的传送。RTP 协议包括RTP 和RTCP(RTP 控制协议) 两个关系十分密切的子协议：<br>&nbsp;&nbsp;&nbsp; (1)&nbsp; RTP协议－传输具有实时特性的数据；<br>&nbsp;&nbsp;&nbsp; （2）RTCP协议-监测QoS 和传送参与传输者的信息。<br>&nbsp;&nbsp;&nbsp; RTP(实时传输协议) 通常工作在UDP的上层，从上层接收多媒体信息码流(如MPEG-4视频) ，组装成RTP 数据包,然后发送给下层UDP ，相当于OSI 的会话层，提供同步和排序服务。故RTP 协议适用于传送连续性强的数据，如视频、音频等，并对网络引起的时延差错有一定的自适应能力。RTCP 为实时控制协议，用于管理控制信息，如监视网络的延时和带宽，一旦所传输的多媒体信息的带宽发生变化，接收端则通知发送端，广播符号化识别码和编码参数， 达到控制传输质量的目的。此外,如果底层网络支持多点传播的话，RTP 还支持使用多点传播向多个目的端点发送数据。<br>&nbsp;&nbsp;&nbsp; RTP协议具有如下特点[5]：<br>（1）灵活性<br>&nbsp;&nbsp;&nbsp; RTP协议的数据报文和控制报文使用不同的端口，数据流和控制流分离，这样大大地提高了协议的灵活性，处理也简单。<br>（2）支持多播<br>&nbsp;&nbsp;&nbsp; 如果下层网路支持，可以支持多播。<br>（3）可扩展性<br>&nbsp;&nbsp;&nbsp; RTP协议通常为一个具体的应用提供服务，通过一个具体的应用进程实现，而不作为OSI体系结构中单独的一层来实现，RTP只提供协议框架，开发者可以根据应用的具体要求对协议进行充分的扩展。<br><br><strong>3 关键技术的实现<br><br></strong>&nbsp;&nbsp; &nbsp;该系统的发送端实现思路如下：用USB摄像头采集数据，用Divx 5.1.1 Codec 对采集到的数据进行MPEG-4的编码，然后连到一个发送Filter把编码后的数据发送出去。其Filter Graph如图1所示 ：
<p><a href="http://www.51kaifa.com/upload/2005/09/1127014532.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127014532.gif" align=absMiddle border=0></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图1&nbsp;&nbsp; 发送端的Filter Graph<br>&nbsp;&nbsp; 接收端的实现思路如下:通过一个接收Filter接收发送端发送的数据，然后再用Divx Decoder Filter对接收到的数据进行解码。最后用Video Renderer把解码后的数据播放出来。其Filter Graph如图2所示：<br><strong><a href="http://www.51kaifa.com/upload/2005/09/1127014559.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127014559.gif" align=absMiddle border=0></a></strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图2&nbsp;&nbsp; 接收端的Filter Graph<br><strong>3.1&nbsp; 数据采集及编码的实现<br>3.1.1 采集Filter Graph的实现</strong><br>&nbsp;&nbsp;&nbsp; 采集应用的Filter Graph一般比较复杂，而直接使用Filter Graph Manager上的IGraphBuilder接口构建这种Filter Graph,有时候难度又很大。为此，DirectShow特别提供了一个辅助组件Capture Graph Builder,来简化这种Filter Graph的创建。<br>&nbsp;&nbsp;&nbsp; 首先是创建Filter Graph Manager 组件，核心代码如下：<br>&nbsp;<a href="http://www.51kaifa.com/upload/2005/09/1127014607.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127014607.gif" align=absMiddle border=0></a></p>
<p>3.1.2 加入采集Filter<br><a href="http://www.51kaifa.com/upload/2005/09/1127014654.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127014654.gif" align=absMiddle border=0></a><br><strong>3.1.3加入MPEG-4编码器Filter</strong><br>&nbsp;&nbsp;&nbsp; 这里我们采用Divx 提供的开源编码Filter。安装DivX.Pro.v5.1.1后会自动安装Divx的编码器Filter和解码器Filter（注：解码器 Filter在接收端要用到）。在程序中加入Divx的编码器Filter，实现思想是在Video Compressors目录下枚举到名称为"DivX Pro(tm) 5.1.1 Codec"的Filter项后，把它加入到Filter Graph中即可。<br><strong>3.2 数据的发送和接收<br>3.2.1 数据的发送Filter的实现</strong>&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; 数据的发送要开发一个发送Filter，为了编程上的方便，这里采用程序内Filter的形式来实现。即用类的形式而不是编写一个成一个后缀为ax的组件 注册后再使用。这里我们定义一个继承自CBaseFilter的类CFilterMpeg4Sender。这个类必须实现以下功能[3]：<br>&nbsp;&nbsp; (1) 在类中定义CFilterMpeg4Sender上的Pin的实例mInputPin。<br>&nbsp;&nbsp; (2) 实现继承自CBaseFilter::GetPin,用于返回Filter上各个Pin的对象指针。<br>&nbsp;&nbsp; (3) 实现继承自CBaseFilter::GetPin,用于返回Filter上各个Pin的数量。<br>&nbsp;&nbsp;&nbsp; 定义一个继承自CRenderedInputPin的类CMpeg4InputPin，用于实现CFilterMpeg4Sender上的输入pin，发送Filter通过该输入pin接收编码Filter输出的数据，然后按一定的规则发送。<br>&nbsp;&nbsp;&nbsp; 这个类必须实现以下功能[2]：<br>&nbsp;&nbsp; (1) 重写方法EndOfStream。<br>&nbsp;&nbsp; (2) 实现IPin::BeginFlush和IPin::EndFlush两个函数。<br>&nbsp;&nbsp; (3) 重写方法CBasePin::CheckMediaType进行连接时媒体类型的检查。<br>&nbsp;&nbsp; (4) 重写方法CBasePin:: Receive(),接收Sample并发送<br><strong>3.2.2 数据的接收Filter的实现 <br></strong>数 据的接收其实是要编写一个Source Filter, 这个Source Filter名称为CFilterMpeg4Receiver，也继承自CBaseFilter。这跟发送Filter的实现有些类似，有一点需要注意的 是该Filter输出的MediaType的设置。<br>&nbsp;&nbsp;&nbsp;&nbsp; Char&nbsp; MediaType[]=//媒体数据类型,通过在发送端把媒体类型写到一个文件中而得到然后通过语句：CFilterMpeg4Receiver:: SetupMediaType((char *)MediaType,88)设置输出数据的MediaType。<br>&nbsp;&nbsp;&nbsp; CFilterMpeg4Receiver::SetupMediaType再调用CMpeg4OutPin::SetupMediaType（）设置、接收到的媒体数据的格式，<br><strong>3.2.3 数据的网络传输的实现</strong><br>&nbsp; <br>&nbsp;<br>&nbsp;&nbsp;&nbsp; &nbsp;数据的发送我们采用开源代码JRTPLIB【6】提供的RTP协议栈。最新的JRTPLIB对RFC3550的实现进行了封装，开发人员只要初步了解 RTP协议就可以开发出高质量的音视频传输程序。使用JRTPLIB时，只需要通过继承RTPSession类，再重新以下几个函数就可以实现视频数据的 接收。</p>
<p><a href="http://www.51kaifa.com/upload/2005/09/1127014790.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127014790.gif" align=absMiddle border=0></a><br>&nbsp;&nbsp;&nbsp;&nbsp; 在网络带宽比较低的情况下（如十几KBps），数据丢帧现象比较严重，这对于图像质量有很大的影响。我们采用拆帧（拆成1400个字节）以后再发送的方法，来降低丢帧率。接收端收到数据后，再把属于同一视频帧的数据再组起来。<br>&nbsp;&nbsp;&nbsp; 网络发送接收程序流程图如图3所示：<br><a href="http://www.51kaifa.com/upload/2005/09/1127014983.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127014983.gif" align=absMiddle border=0></a></p>
<p align=center>图3&nbsp; 网络发送接收程序流程图</p>
<p><br>&nbsp;&nbsp;&nbsp; 对程序流程图的说明如下：<br>（1）发送端拆帧的算法如下：<br><a href="http://www.51kaifa.com/upload/2005/09/1127015172.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127015172.gif" align=absMiddle border=0></a><br>&nbsp;&nbsp; 然后把属于同一视频帧的数据组好，发送到解码Filter。<br>&nbsp;&nbsp; 经过测试（在CDMA1.X网络下），采用拆帧方法传输视频数据比直接发送丢包率更低，传输质量有了很大的提高。<br><strong>3.3 数据解码及回放的实现<br></strong>&nbsp;&nbsp;&nbsp; 解码Filter使用的是Divx提供的开源解码器，在接收Filter的后面接上该解码Filter即可，最后接上Renderer Filter就可以把接收到的数据回放出来。<br><strong>3.4 实现帧率控制功能<br></strong>&nbsp;&nbsp;&nbsp; 通过在采集设备和编码Filter（DivX Pro(tm) 5.1.1 Codec）之间加入一个帧率控制Filter来实现帧率的控制，该Filter相当于一个视频帧数计数器，每接收到一帧，并不立即把该帧发给下游的编码 Filter，而是把计数器的值加1，当计数器的值达到最大值时才把当前收到的帧发出去。在接收端发控制帧率命令给采集端可以很方便的实现帧率的远端控 制。<br>&nbsp;&nbsp;&nbsp; 程序片断如下：<br><a href="http://www.51kaifa.com/upload/2005/09/1127015392.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127015392.gif" align=absMiddle border=0></a><br>&nbsp;&nbsp;&nbsp; 加了帧率控制Filter的发送端 Filter Graph 如图4所示：</p>
<p><a href="http://www.51kaifa.com/upload/2005/09/1127015643.gif" target=_blank><img alt="" src="http://www.51kaifa.com/upload/2005/09/1127015643.gif" align=absMiddle border=0></a><br>图4&nbsp;&nbsp; 实现了帧率控制的Filter Graph&nbsp; </p>
<p><strong>4 总结</strong></p>
<p>&nbsp;&nbsp;&nbsp; 该系统采用了DirectShow技术实现了MPEG-4视频数据的传输，视频数据的传输采用了RTP协议。而且还实现了远端帧率的控制，该系统可以很方 便的移植到未来3G网络的图像传输系统中。对编解码器进行研究，采用H.264技术实现编解码Filter是下一步要完成的工作，当然在传输质量 （QoS）方面也要深入进行研究。</p>
<p><strong>参考文献</strong></p>
1&nbsp; 邵林,曹汉强.基于DiectShow的视频广播系统设计与实现[J].微型机与应用,2004, 4 :58-60<br>2&nbsp; Microsoft DirectX C++ SDK Document [EB/OL],2003<br>3&nbsp; 陆其明.DiectShow开发指南[M].北京.清华大学出版社,2004<br>4&nbsp; 陆其明.DiectShow实务精选[M].北京:科学出版社,2004<br>5&nbsp; 张明华.《基于RTP的视频传输控制方法的研究》[D].郑州市：郑州大学, 2004.3<br>6&nbsp; Jori Liesenborgs&nbsp;&nbsp; JRTPLIB 3.1.0 [EB/OL]&nbsp;
<img src ="http://www.cppblog.com/niewenlong/aggbug/32782.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-09-24 14:47 <a href="http://www.cppblog.com/niewenlong/archive/2007/09/24/32782.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用DirectShow实现QQ的音视频聊天功能</title><link>http://www.cppblog.com/niewenlong/archive/2007/09/24/32781.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 24 Sep 2007 06:45:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/09/24/32781.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/32781.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/09/24/32781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/32781.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/32781.html</trackback:ping><description><![CDATA[当下比较流行的即时通信工具，比如MSN，QQ等都实现了视音频的功能，通过视频，音频，我们可以更好的和朋友通过网络进行沟通，本文通过DirectShow技术模拟QQ实现了视频和音频的采集，传输，基本实现了QQ的视音频聊天的功能。
<div><span></span></div>
　　网络视音频系统主要功能就在于视音频的采集，网络传输两个方面，通过Video Capture系列API函数，你就可以轻松的搞定视频捕捉，但是对于视频的网络传输，则要费一番功夫了。 对于视音频数据的传输，只简单地使用数据报套接字传输音视频数据是不可行的，还必须在UDP层上采用RTP（实时传输协议）和RTCP（实时传输控制协议）来改善服务质量。实时传输协议提供具有实时特征的、端到端的数据传输服务。我们在音视频数据前插入包含有载荷标识、序号、时间戳和同步源标识符的RTP包头，然后利用数据报套接字在IP网络上传输RTP包，以此改善连续重放效果和音视频同步。实时传输控制协议RTCP用于RTP的控制，它最基本的功能是利用发送者报告和接收者报告来推断网络的服务质量，若拥塞状况严重，则改用低速率编码标准或降低数据传输比特率，以减少网络负荷，提供较好的Q.S保证。<br><br>　　Directshow对于音视频的采集提供了很好的接口，利用ICaptureGraphBuilder2接口可以很轻松的建立起视频捕捉的graph图，通过枚举音频设备Filter，也可以很轻松的实现音频的捕捉，有点麻烦的是音视频数据的传输，我们可以自己封装RTP和RTCP的协议，来自己实现一个filter，用来发送和接收音视频数据，当然了Directshow也提供了一组支持使用RTP协议的网络传输多媒体流的Filters。你也完全可以用Directshow提供的RTP系列的filter实现数据的传输。<br><br>　　下面分析一下这些RTP Filters。<br><br>　　新定义的Filter包括 RTP Source Filter ，RTP Render Filter，RTP Demux Filter，RTP Receive Playload Handler (RPH) filter，RTP Send Payload (SPH) filter，使用这5个filter构建一个通过RTP协议传输音视频数据的Graph是没有问题的。<br><br>　　RTP Source filter被用来从一个单独的RTP<a href="http://www.yesky.com/key/113/80113.html" target=_blank><u><font color=#96b0af size=2>会话</font></u></a>中接收RTP和RTCP包。这个filter提供一个指定发送给其它主机RTCP接收器报告和指定网络地址和端口接口来接收RTP会话的接口。<br><br>　　RTP Rend filter是用来将数据发到网络上的一个filter，这个filter也提供了和RTP source Filter 类似的接口。<br><br>　　RTP Demux filter用来多路分离来自 RTP Source filter的RTP 包，这个filter有一个或者多个输出的pin。这个Filter提供了如何控制多路分离和如何分配到特定输出pin的接口。<br><br>　　RTP RPH Filter 是用来网络过来的RTP包还原成原来的数据格式，主要支持H.261，H.263，Indeo，G.711，G.723和G.729和常见的多种音视频负载类型。<br><br>　　RTP SPH filter则和RPH filter的功能相对，它的任务是将音视频 压缩filter输出的 数据分解为RTP包，它提供的接口有指定最大生成包大小和pt值。<br><br>　　下面我们看看<a href="http://www.yesky.com/key/200/65200.html" target=_blank><u><font color=#96b0af size=2>如何用</font></u></a>这些filter来搭建我们采集和传输的graph图。<br><br>
<table align=center border=0>
    <tbody>
        <tr>
            <td>
            <div align=center><img src="http://dev.yesky.com/imagelist/05/07/i033323zvy42.jpg" border=0><br><br><img src="http://dev.yesky.com/imagelist/05/07/1106yxef0jbu.jpg" border=0></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　图1和图2展示了DirectShow RTP中定义的filters如何运用。图1是一个采集本地多媒体数据并使用RTP协议通过网络发送的filter graph。它包含一个输出原始视频帧的视频采集filter，紧跟一个压缩帧的编码filter。一旦压缩，这些帧就会被发送到RTP SPH filter，分片打包，生成RTP包，对应的发送到 RTP Render filter，通过网络传输这些包。图2展现了一个filter graph，用来接收包含视频流RTP包，播放视频。这个graph由一个用来接收包的RTP Source filter，一个根据源和负载类型进行分类的RTP Demux filter，一个把RTP包转为压缩视频帧的RTP RPH filter组成。这些filter随后的是用来解压帧的解码filter，一个显示未压缩帧的渲染filter。<br><br>　　有了RTP filter的帮助我们就可以完成类似qq的功能了，可以实现在网络上进行视频和音频的交互了，下面我给出在网络上两个客户端A和B进行音频和视频交互的Graph图。这里我对图1和图2中的RTP filter进行了自己封装，将编解码filter直接封装到了RTP Source filter 和RTP Render filter中，这样Graph图就显得很简洁，RTP Source filter只是用来接收网络过来的音视频数据，然后将数据传递给客户程序，RTP Render filter则是将采集到的音视频数据发送到网络上的另一个客户端，编解码则的工作则封装到这两个filter之中。<br><br>
<table align=center border=0>
    <tbody>
        <tr>
            <td>
            <div align=center><img src="http://dev.yesky.com/imagelist/05/07/3vx8wn70kmim.jpg" border=0><br>图3 网络视频和音频交互的Graph图</div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　如果你也想自己封装自己的Source 和Render filter，首先你要选择自己的编解码，视频编解码是选择H261，H263，还是 MEPG4，音频是选择G729还是G711，要首先确定好。选好编解码，封装的工作就简单了。<br><br>　　不多说了，下面看看我给出的代码吧。<br><br>　　首先要定义一下用到的四个RTP filter的CLSID。<br><br>
<table align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>static const GUID CLSID_FG729Render = { 0x3556f7d8, 0x5b5, 0x4015, { 0xb9, 0<a href="http://www.yesky.com/key/1001/96001.html" target=_blank><u><font color=#96b0af>x40</font></u></a>, 0x65, 0xb8, 0<a href="http://www.yesky.com/key/980/95980.html" target=_blank><u><font color=#96b0af>x8</font></u></a>, 0x94, 0xc8, 0xf9 } }; //音频发送 <br>static const GUID CLSID_FG729Source = { 0x290bf11a, 0x93b4, 0x4662, { 0xb1, 0xa3, 0xa, 0x53, 0x51, 0xeb, 0xe5, 0x8e } };//音频接收<br>static const GUID CLSID_FH263Source = { 0xa0431ccf, 0x75db, 0x463e, { 0xb1, 0xcd, 0xe, 0x9d, 0xb6, 0x67, 0xba, 0x72 } };//视频接收<br>static const GUID CLSID_FH263Render = { 0x787969cf, 0xc1b6, 0x41c5, { 0xba, 0xa8, 0x4e, 0xff, 0xa3, 0xdb, 0xe4, 0x1f } };//视频发送<br>//发送和接收音视频数据的filter<br>CComPtr&lt; IBaseFilter &gt; m_pAudioRtpRender ;<br>CComPtr&lt; IBaseFilter &gt; m_pAudioRtpSource ;<br>CComPtr&lt; IBaseFilter &gt; m_pVideoRtpRender ;<br>CComPtr&lt; IBaseFilter &gt; m_pVideoRtpSource ;<br><br>char szClientA[100];<br>int iVideoPort = 9937;<br>int iAudioPort = 9938;<br><br>//构建视频的graph图,并发送数据<br>CComPtr&lt; IGraphBuilder &gt; m_pVideoGraphBuilder; //视频图形管理器 <br>CComPtr&lt; ICaptureGraphBuilder2 &gt; m_pVideoCapGraphBuilder; <br>CComPtr&lt; IBaseFilter &gt; m_pFilterVideoCap;<br>CComPtr&lt; IVideoWindow &gt; m_pVideoWindow;<br>CComPtr&lt; IMediaControl &gt; m_pVideoMediaCtrl ;<br>CComPtr&lt; IBaseFilter &gt; m_pVideoRenderFilter;<br><br>HRESULT CMyDialog::VideoGraphInitAndSend()<br>{<br>　HRESULT hr;<br>　hr =m_pVideoGraphBuilder.CoCreateInstance( CLSID_FilterGraph );<br>　if(FAILED(hr))<br>　　return hr;<br>　hr =m_pVideoCapGraphBuilder.CoCreateInstance( CLSID_CaptureGraphBuilder2);<br>　if(FAILED (hr))<br>　　return hr;<br>　m_pVideoCapGraphBuilder-&gt;SetFiltergraph(m_pVideoGraphBuilder);<br>　m_pVideoGraphBuilder-&gt;QueryInterface(IID_IMediaControl, (<a href="http://www.yesky.com/key/3728/98728.html" target=_blank><u><font color=#96b0af>void</font></u></a> **)&amp;m_pVideoMediaCtrl);<br>　m_pVideoGraphBuilder-&gt;QueryInterface(IID_IVideoWindow,(void**)&amp;m_pVideoWindow)<br><br>　FindDeviceFilter(&amp;m_pFilterVideoCap,CLSID_VideoInputDeviceCategory);<br>　if(m_pFilterVideoCap)<br>　　m_pVideoGraphBuilder-&gt;AddFilter( m_pFilterVideoCap,T2W("VideoCap") ) ;<br>　　//创建预览的filter<br>　hr = m_pRenderFilterVideo.CoCreateInstance(CLSID_VideoRenderer);<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pVideoGraphBuilder-&gt;AddFilter( m_pRenderFilterVideo, L"VideoRenderFilter" );<br>　Connect(m_pFilterVideoCap ,m_pRenderFilterVideo) ;<br>　//设置预览的窗口<br><br>　CRect rc ; <br>　GetClientRect(m_hOwnerWnd, &amp;rc );<br>　int iWidth = rc.right - rc.left ;<br>　int iHeight = rc.bottom - rc.top ;<br>　int iLeft, iTop;<br>　if((iHeight*1.0)/(iWidth*1.0) &gt;= 0.75)<br>　{<br>　　//按宽度算<br>　　int tmpiHeight = iWidth*3/4;<br>　　iTop = (iHeight - tmpiHeight)/2;<br>　　iHeight = tmpiHeight;<br>　　iLeft = 0;<br>　}<br>　else<br>　{<br>　　//按高度算<br>　　int tmpiWidth = iHeight*4/3;<br>　　iLeft = (iWidth - tmpiWidth)/2;<br>　　iWidth = tmpiWidth;<br>　　iTop = 0;<br>　} <br>　m_pVideoWindow-&gt;put_Owner( (OAHWND) m_hPreviewWnd ) ;<br>　m_pVideoWindow-&gt;put_Visible( OATRUE );<br>　m_pVideoWindow-&gt;put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS ) ;<br><br>　//连接到网络并发送<br>　CComPtr&lt; IRtpOption &gt; pRenderOption; <br>　CComPtr&lt; IVideoOption &gt; pVideoOption;<br><br>　tagVideoInfo vif(160,120,24);<br>　int t=((int)(m_iFrameRate/5)*5)+5;<br>　vif.nBitCount=24;<br>　vif.nWidth=160;<br>　vif.nHeight=120;<br><br>　hr = ::CoCreateInstance(CLSID_FH263Render, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&amp;m_pVideoRtpRender);<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pVideoRtpRender-&gt;QueryInterface(IID_IJRTPOption, (void**)&amp;pRenderOption);<br>　m_pVideoRtpRender-&gt;QueryInterface(IID_IVideoOption,(void**)&amp;pVideoOption); <br>　pVideoOption-&gt;SetProperty(&amp;vif);<br>　pVideoOption-&gt;SetSendFrameRate(m_iFrameRate,1);//1 不发送数据，0 实际发送数据<br>　Connect(m_pFilterVideoCap ,m_pVideoRtpRender) ;<br>　//连接对方<br>　hr= pRenderOption-&gt;Connect(szClientA,iVideoPort,1024);<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pVideoMediaCtrl-&gt;Run();<br>}<br>//视频的接收<br>CComPtr&lt; IGraphBuilder &gt; m_pVideoGraphBuilder; //视频图形管理器 <br>CComPtr&lt; IBaseFilter &gt; m_pFilterVideoCap;<br>CComPtr&lt; IVideoWindow &gt; m_pVideoWindow;<br>CComPtr&lt; IMediaControl &gt; m_pVideoMediaCtrl ;<br>CComPtr&lt; IBaseFilter &gt; m_pVideoRenderFilter;<br>HWND m_hRenderWnd ;<br>HRESULT VideoRecive()<br>{<br>　HRESULT hr;<br>　hr=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,<br>　IID_IFilterGraph,(void**)&amp;m_pVideoGraphBuilder);<br><br>　m_pVideoGraphBuilder-&gt;QueryInterface(IID_IMediaControl, (void **)&amp;m_pVideoMediaCtrl);<br>　m_pVideoGraphBuilder-&gt;QueryInterface(IID_IVideoWindow,(void**)&amp;m_pVideoWindow)<br>　<br>　hr = ::CoCreateInstance(CLSID_FH263Source, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&amp;m_pVideoRtpSource);<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pVideoGraphBuilder-&gt;AddFilter(m_pVideoRtpSource, L"My Custom Source");<br><br>　CComPtr&lt; IRtpOption &gt; m_pRtpOption; <br>　CComPtr&lt; IVideoOption &gt; m_pVideoOption;<br>　m_pVideoRtpSource-&gt;QueryInterface(IID_IJRTPOption, (void **)&amp;m_pRtpOption);<br>　m_pVideoRtpSource-&gt;QueryInterface(IID_IVideoOption, (void **)&amp;m_pVideoOption);<br><br>　tagVideoInfo vif(160, 120 ,24);<br>　m_pVideoOption-&gt;SetProperty(&amp;vif);<br>　hr= pRenderOption-&gt;Connect(szClientA,iVideoPort +1,1024);<br>　if(FAILED(hr))<br>　　return hr;<br><br>　//创建预览的filter<br>　hr = m_pRenderFilterVideo.CoCreateInstance(CLSID_VideoRenderer);<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pVideoGraphBuilder-&gt;AddFilter( m_pRenderFilterVideo, L"VideoRenderFilter" );<br>　Connect(m_pVideoRtpSource ,m_pRenderFilterVideo) ; <br><br>　CRect rc ; <br>　GetClientRect(m_hOwnerWnd, &amp;rc );<br>　int iWidth = rc.right - rc.left ;<br>　int iHeight = rc.bottom - rc.top ;<br>　int iLeft, iTop;<br>　if((iHeight*1.0)/(iWidth*1.0) &gt;= 0.75)<br>　{<br>　　//按宽度算<br>　　int tmpiHeight = iWidth*3/4;<br>　　iTop = (iHeight - tmpiHeight)/2;<br>　　iHeight = tmpiHeight;<br>　　iLeft = 0;<br>　}<br>　else<br>　{<br>　　//按高度算<br>　　int tmpiWidth = iHeight*4/3;<br>　　iLeft = (iWidth - tmpiWidth)/2;<br>　　iWidth = tmpiWidth;<br>　　iTop = 0;<br>　} <br>　m_pVideoWindow-&gt;put_Owner( (OAHWND) m_hRenderWnd ) ;<br>　m_pVideoWindow-&gt;put_Visible( OATRUE );<br>　m_pVideoWindow-&gt;put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS ) ; <br>　m_pVideoMediaCtrl-&gt;Run();<br><br>　return S_OK;<br>}<br>//<br>HRESULT FindDeviceFilter(IBaseFilter ** ppSrcFilter,GUID deviceGUID)<br>{<br>　HRESULT hr;<br>　IBaseFilter * pSrc = NULL;<br>　CComPtr &lt;IMoniker&gt; pMoniker =NULL;<br>　ULONG cFetched;<br><br>　if (!ppSrcFilter)<br>　　return E_POINTER;<br><br>　// Create the system device enumerator<br>　CComPtr &lt;ICreateDevEnum&gt; pDevEnum =NULL;<br><br>　hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,<br>　IID_ICreateDevEnum, (void **) &amp;pDevEnum);<br>　if (FAILED(hr))<br>　　return hr;<br><br>　// Create an enumerator for the video capture devices<br>　CComPtr &lt;IEnumMoniker&gt; pClassEnum = NULL;<br><br>　hr = pDevEnum-&gt;CreateClassEnumerator (deviceGUID, &amp;pClassEnum, 0);<br>　if (FAILED(hr))<br>　　return hr;<br><br>　if (pClassEnum == NULL)<br>　　return E_FAIL;<br><br>　if (S_OK == (pClassEnum-&gt;Next (1, &amp;pMoniker, &amp;cFetched)))<br>　{<br>　　hr = pMoniker-&gt;BindToObject(0,0,IID_IBaseFilter, (void**)&amp;pSrc);<br>　　if (FAILED(hr))<br>　　　return hr;<br>　}<br>　else<br>　　return E_FAIL;<br><br>　*ppSrcFilter = pSrc;<br><br>　return S_OK;<br>}<br><br>//构建音频Graph图，并发送<br>CComPtr&lt; IGraphBuilder &gt; m_pAudioGraphBuilder; //音频图形管理器 <br>CComPtr&lt; ICaptureGraphBuilder2 &gt; m_pCapAudioGraphBuilder; <br>CComPtr&lt; IBaseFilter &gt; m_pFilterAudioCap;<br>CComPtr&lt; IMediaControl &gt; m_pAudioMediaCtrl ;<br><br>HRESULT AudioGraphInit()<br>{<br>　HRESULT hr;<br>　hr =m_pAudioGraphBuilder.CoCreateInstance( CLSID_FilterGraph );<br>　if(FAILED(hr))<br>　　return hr;<br>　hr =m_pCapAudioGraphBuilder.CoCreateInstance( CLSID_CaptureGraphBuilder2);<br>　if(FAILED (hr))<br>　　return hr;<br>　m_pAudioGraphBuilder-&gt;SetFiltergraph(m_pCapAudioGraphBuilder);<br>　m_pAudioGraphBuilder-&gt;QueryInterface(IID_IMediaControl, (void **)&amp;m_pAudioMediaCtrl);<br><br>　FindDeviceFilter(&amp;m_pFilterVideoCap,CLSID_AudioInputDeviceCategory);<br>　if(m_pFilterAudioCap)<br>　　m_pAudioGraphBuilder-&gt;AddFilter( m_pFilterAudioCap,T2W("AudioCap") ) ;<br><br>　//发送到网络<br>　hr =::CoCreateInstance(CLSID_FG729Render,NULL,CLSCTX_INPROC,<br>　IID_IBaseFilter,(void**)&amp;m_pFilterRtpSendAudio)<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pAudioGraphBuilder-&gt;AddFilter(m_pAudioRtpRender, L"FilterRtpSendAudio");<br>　Connect(m_pFilterAudioCap,m_pAudioRtpRender);<br><br>　CComPtr&lt; IRtpOption &gt; pOption ;<br>　m_pAudioRtpRender-&gt;QueryInterface(IID_IJRTPOption,(void**)&amp;pOption)<br>　hr =pOption-&gt;Connect(szClientA,iAudioPort,1024);<br>　if(FAILED(hr))<br>　　return hr;<br><br>　m_pAudioMediaCtrl-&gt;Run();<br>　return S_OK;<br>}<br>//音频的接收 <br>CComPtr&lt; IGraphBuilder &gt; m_pAudioGraphBuilder; //音频图形管理器 <br>CComPtr&lt; ICaptureGraphBuilder2 &gt; m_pCapAudioGraphBuilder; <br>CComPtr&lt; IBaseFilter &gt; m_pFilterAudioCap;<br>CComPtr&lt; IMediaControl &gt; m_pAudioMediaCtrl ;<br>CComPtr&lt;IBaseFilter&gt; m_pAudioRender;<br>HRESULT AudioRecive()<br>{<br>　HRESULT hr;<br>　hr =m_pAudioGraphBuilder.CoCreateInstance( CLSID_FilterGraph );<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pAudioGraphBuilder-&gt;QueryInterface(IID_IMediaControl, (void **)&amp;m_pAudioMediaCtrl);<br><br>　hr = m_pAudioRtpSource-&gt;CoCreateInstance(CLSID_FG729Source) ;<br>　if(FAILED(hr))<br>　　return hr;<br>　m_pAudioGraphBuilder-&gt;AddFilter(m_pAudioRtpSource,L"AudioRtp");<br>　//创建声卡Renderfilter<br>　FindDeviceFilter(&amp;m_pAudioRender,CLSID_AudioRendererCategory);<br>　m_pAudioGraphBuilder-&gt;AddFilter(m_pAudioRender,L"AudioRender");<br>　CComPtr&lt; IRtpOption &gt; pRtpOption ;<br>　m_pAudioRtpSource-&gt;QueryInterface(IID_IJRTPOption,(void**)&amp;pRtpOption)<br>　hr= pRtpOption-&gt;Connect(szClientA,iAudioPort+2,1024);<br>　if(FAILED (hr))<br>　　return hr;<br><br>　Connect(m_pAudioRtpSource,m_pAudioRender);<br>　<br>　m_pAudioMediaCtrl-&gt;Run();<br>　return S_OK;<br>}</td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/niewenlong/aggbug/32781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-09-24 14:45 <a href="http://www.cppblog.com/niewenlong/archive/2007/09/24/32781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>