基于DirectShow的MPEG-4视频传输系统的研究与实现(转载)

最近一直忙于工作,要换工作了,所以一直没有时间写文章了,一直关心我blog的朋友们估计,又要说我不更新了,加上自从写了Directshow实现qq的音视频传输一文后,有很多朋友发email,询问相关的问题,正好我再网上看到这篇文章,贴到这里,我们一起学习吧,向本文的作者表示感谢,如果你觉得转载该文侵犯了您的权利,请及时通知我
基于 DirectShow MPEG-4 视频传输系统的研究与实现
温小明   吴志刚
(东华大学计算机学院 上海 200051)
摘要   本文简单介绍了DirectShow技术,研究了利用DirectShow实现视频采集、压缩和网络传输技术。并利用第三方提供的编解码器实现了MPEG-4视频数据的网络传输系统,在该系统中利用RTP协议进行视频数据传输,同时实现了远端帧率的控制。
关键词 视频; 采集; 压缩; DirectShow; MPEG-4,RTP
1 引言
近年来,随着国民经济的发展,社会各个部门对于视频监视系统的需求越来越多。但目前的很多监视系统都跟具体的硬件相关,必须要具体的采集卡的支持才能实现。所以有必要开发一种具有通用性的视频监视系统,用普通的摄像头就能实现视频的采集。
基于 DirectShow 的开发能很灵活地控制音视频的效果,所以选择 DirectShow 这种可扩展性好的技术做开发对以后的应用升级很有帮助。 此外,为了实现流媒体传输控制的策略,流媒体的传输和回放也是应解决的问题之一。由 Microsoft 提供的 DirectShow 技术基于组件对象模型技术,支持宽松的格式变化,提供高品质的多媒体流回放。利用它可以在普通微机中实现流媒体的客户端处理,并可以提高系统的通用性和可扩展性。
对于视频数据的传输,压缩率是一个必须考虑到的因素。 MPEG-4 是由 ISO IEC MPEG 组制定的一个关于活动图像和声音的编码国际标准。它在基于内容的交互性、压缩率、通用访问能力等方面提供了一系列新的或改进的功能。 MPEG-4 视频在提供较好的图像质量的同时拥有较高的压缩率,适合于作为传输的图像压缩标准。
相关技术
2.1 DirectShow 技术简介
         DirectShow Microsoft 为开发高性能多媒体应用而开发的底层应用程序接口( API , 它是 DirectX 家族的核心成员之一。 DirectShow 自身是通过一种系统内置的或程序员开发的过滤器( Filter )来控制和处理多媒体数据的体系结构。该体系结构定义了如何处理和控制过滤器内部及相互之间的多媒体数据流。每个过滤器都有输入或输出针( Pin , 或两者都有。
    过滤器( Filter )是 DirectShow 的基本组成部分,是 Filter Graph( 过滤器图 ) 中最小的功能模块, DirectShow 将多媒体数据的处理分离成不同的步骤,这些不同的步骤由相应的 Filter 去处理。这样我们可以把不同的过滤器搭配在一起达到我们要求的来处理多媒体数据。过滤器根据实现功能的不同大致可分为 3 类:
1                     源过滤器( Source Filters )。源过滤器负责得到原始媒体数据。这些媒体数据的来源包括本地硬盘或网络上的媒体文件、各种采集卡等。
2                     转换过滤器( Transform Filters )。转换过滤器的任务是处理从其他过滤器中接收的数据,经过一定的处理后再传递给下一个过滤器。编解码器就是典型的转换过滤器。
3                     表现过滤器( Rendering Filters )。表现过滤器对接收到的数据进行最后的处理。它做的工作有:把媒体数据保存为文件、将数据发送到网络、显示视频、回放音频等 [1]
DirectShow 系统之上是应用程序 (Application) 。应用程序要按照程序所要实现的功能建立起相应的 Filter Graph , 然后借助于 Filter Graph Manager 来控制整个数据的处理过程。 DirectShow 能在 Filter Graph 运行的时候接收到各种事件 , 并通过消息的方式发送到应用程序。这样就实现了应用程序与 DirectShow 系统之间的交互。
2.2 RTP/RTCP 协议介绍
实时传输协议 RTP(Realtime Transport Protocol) 是针对 Internet 上多媒体数据流的一个传输协议 1996 年由 IETF( Internet 工程任务组 ) AVT 小组作为 RFC1889 发布 AVT 小组后来对该文档进行了不断改进 2003 7 月提出了代替 RFC1889 RFC3550 RTP 充分体现了应用层分帧这一现代通信协议的设计思想,允许其用户了解、调整甚至制定连续媒体的打包方案,该协议被广泛用于 VoIP 、视频等实时媒体的传送。 RTP 协议包括 RTP RTCP(RTP 控制协议 ) 两个关系十分密切的子协议:
(1) RTP 协议-传输具有实时特性的数据;
2 RTCP 协议 监测 QoS 和传送参与传输者的信息。
RTP( 实时传输协议 ) 通常工作在 UDP 的上层,从上层接收多媒体信息码流 ( MPEG-4 视频 ) ,组装成 RTP 数据包 , 然后发送给下层 UDP ,相当于 OSI 的会话层,提供同步和排序服务。故 RTP 协议适用于传送连续性强的数据,如视频、音频等,并对网络引起的时延差错有一定的自适应能力。 RTCP 为实时控制协议,用于管理控制信息,如监视网络的延时和带宽,一旦所传输的多媒体信息的带宽发生变化,接收端则通知发送端,广播符号化识别码和编码参数,达到控制传输质量的目的。此外 , 如果底层网络支持多点传播的话, RTP 还支持使用多点传播向多个目的端点发送数据。
RTP 协议具有如下特点 [5]
1 )灵活性
RTP 协议的数据报文和控制报文使用不同的端口,数据流和控制流分离,这样大大地提高了协议的灵活性,处理也简单。
2 )支持多播
如果下层网路支持,可以支持 多播。
3 )可扩展性
 
RTP 协议通常为一个具体的应用提供服务,通过一个具体的应用进程实现,而不作为 OSI 体系结构中单独的一层来实现, RTP 只提供协议框架,开发者可以根据应用的具体要求对协议进行充分的扩展。
3 关键技术的实现
   该系统的发送端实现思路如下:用 USB 摄像头采集数据,用 Divx 5.1.1 Codec 对采集到的数据进行 MPEG-4 的编码,然后连到一个发送 Filter 把编码后的数据发送出去。其 Filter Graph 如图 1 所示
 
                       1   发送端的 Filter Graph
 
   接收端的实现思路如下 : 通过一个接收 Filter 接收发送端发送的数据,然后再用 Divx Decoder Filter 对接收到的数据进行解码。最后用 Video Renderer 把解码后的数据播放出来。其 Filter Graph 如图 2 所示:
 
                      图2    接收端的Filter Graph
3.1  数据采集及编码的实现
3.1.1 采集 Filter Graph 的实现
   采集应用的 Filter Graph 一般比较复杂,而直接使用 Filter Graph Manager 上的 IGraphBuilder 接口构建这种 Filter Graph, 有时候难度又很大。为此, DirectShow 特别提供了一个辅助组件 Capture Graph Builder, 来简化这种 Filter Graph 的创建。
首先是创建 Filter Graph Manager 组件,核心代码如下:
hr=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,(void **)&m_pIGraphBuilder);
然后创建一个 Capture Graph Builder 组件,利用这个组件上的 ICaptureGraphBuilder2 接口来完成 Filter Graph 的构建。
hr=CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,CLSCTX_INPROC,
IID_ICaptureGraphBuilder2,(void **)&m_pICaptureGraphBuilder2);
接着通过调用接口方法 ICaptureGraphBuilder2::SetFilterGraph(m_pIGraphBuilder) Filter Graph Manager 对象指针设置给 Capture Graph Builder 组件来完成对它的初始化。
m_pICaptureGraphBuilder2->SetFiltergraph(m_pIGraphBuilder);
3.1.2 加入采集 Filter
    加入采集 Filter 是通过系统枚举的方法来实现的。即在 DirectShow GraphEdit 目录 Video Capture Sources( 对应的 ID 为: CLSID_VideoInputDeviceCategory) 下找到相应的采集设备即可。
    核心代码如下:
hr=CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,(LPVOID *)&pDevEnum);// 创建系统枚举组件对象          
         hr=pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEnum,0);
// 指定枚举的类型目录,获得 IEnumMoniker 接口
         if (hr == S_OK)
         {
IMoniker *pMoniker=NULL;
if(pEnum->Next(1,&pMoniker,NULL)==S_OK)// 假设系统中只有一个采集设备,故枚
// 举到的第一个设备就是符合我们要求的采集设备
{    
hr=pMoniker->BindToObject(0,0,IID_IBaseFilter,(void **)&m_pCapture);
// 创建采集 Filter 实例
}      
枚举到采集设备后,下一步的工作就是把它加入到 Filter Graph 中去。代码如下:
         hr=m_pIGraphBuilder->AddFilter(m_pCapture,L"CaptureFilter");
3.1.3 加入 MPEG-4 编码器 Filter
这里我们采用 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 中即可。
3.2 数据的发送和接收
3.2.1 数据的发送 Filter 的实现   
数据的发送要开发一个发送 Filter ,为了编程上的方便,这里采用程序内 Filter 的形式来实现。即用类的形式而不是编写一个成一个后缀为 ax 的组件注册后再使用。这里我们定义一个继承自 CBaseFilter 的类 CFilterMpeg4Sender 。这个类必须实现以下功能 [3]
   (1) 在类中定义 CFilterMpeg4Sender 上的 Pin 的实例 mInputPin
   (2) 实现继承自 CBaseFilter::GetPin, 用于返回 Filter 上各个 Pin 的对象指针。
   (3) 实现继承自 CBaseFilter::GetPin, 用于返回 Filter 上各个 Pin 的数量。
定义一个继承自 CRenderedInputPin 的类 CMpeg4InputPin ,用于实现 CFilterMpeg4Sender 上的输入 pin ,发送 Filter 通过该输入 pin 接收编码 Filter 输出的数据,然后按一定的规则发送。
这个类必须实现以下功能 [2]
   (1) 重写方法 EndOfStream
   (2) 实现 IPin::BeginFlush IPin::EndFlush 两个函数。
   (3) 重写方法 CBasePin::CheckMediaType 进行连接时媒体类型的检查。
   (4) 重写方法 CBasePin:: Receive(), 接收 Sample 并发送
3.2.2 数据的接收 Filter 的实现
数据的接收其实是要编写一个 Source Filter, 这个 Source Filter 名称为 CFilterMpeg4 Receiver ,也继承自 CBaseFilter 。这跟发送 Filter 的实现有些类似,有一点需要注意的是该 Filter 输出的 MediaType 的设置。
Char MediaType[]=// 媒体数据类型 , 通过在发送端把媒体类型写到一个文件中而得到
然后通过语句: CFilterMpeg4 Receiver::SetupMediaType((char *)MediaType,88) 设置输出数据的 MediaType
CFilterMpeg4 Receiver::SetupMediaType 再调用 CMpeg4OutPin::SetupMediaType ()设置、接收到的媒体数据的格式,
3.2.3 数据的网络传输的实现
   数据的发送我们采用开源代码 JRTPLIB 6 提供的 RTP 协议栈。最新的 JRTPLIB RFC3550 的实现进行了封装,开发人员只要初步了解 RTP 协议就可以开发出高质量的音视频传输程序。使用 JRTPLIB 时,只需要通过继承 RTPSession 类,再重新以下几个函数就可以实现视频数据的接收。
void OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime, const
RTPAddress *senderaddress)
 
    void OnRTCPCompoundPacket(RTCPCompoundPacket *pack, const RTPTime
&receivetime, const RTPAddress *senderaddress)
在网络带宽比较低的情况下(如十几 KBps ),数据丢帧现象比较严重,这对于图像质量有很大的影响。我们采用拆帧(拆成 1400 个字节)以后再发送的方法,来降低丢帧率。接收端收到数据后,再把属于同一视频帧的数据再组起来。
网络发送接收程序流程图如图 3 所示:
 
图3 网络发送接收程序流程图
对程序流程图的说明如下:
1 )发送端拆帧的算法如下:
if ( 该数据帧小于 1400 个字节 )
{
直接用 RTPSessio :: Send() 发送出去。
}
else
{
  把该帧拆成 1400 个字节一个包再发送。对于同一帧数据,我们采用相同的时间戳来标记。
}
2 )接收端组帧算法如下:
while( RTP 包的时间戳和上一个 RTP 包的时间戳相同 )
{
说明该 RTP 包和上一个 RTP 包属于同一个视频帧的数据。
把接收到的数据保存在缓存中。
}
   然后把属于同一视频帧的数据组好,发送到解码 Filter
   经过测试(在 CDMA1.X 网络下),采用拆帧方法传输视频数据比直接发送丢包率更低,传输质量有了很大的提高。
3.3 数据解码及回放的实现
    解码 Filter 使用的是 Divx 提供的开源解码器,在接收 Filter 的后面接上该解码 Filter 即可,最后接上 Renderer Filter 就可以把接收到的数据回放出来。
3.4 实现帧率控制功能
    通过在采集设备和编码 Filter DivX Pro(tm) 5.1.1 Codec )之间加入一个帧率控制 Filter 来实现帧率的控制,该 Filter 相当于一个视频帧数计数器,每接收到一帧,并不立即把该帧发给下游的编码 Filter ,而是把计数器的值加 1 ,当计数器的值达到最大值时才把当前收到的帧发出去。在接收端发控制帧率命令给采集端可以很方便的实现帧率的远端控制。
程序片断如下:
HRESULT CControlFrameFilter::Receive(IMediaSample * pSample)
{
static int sampleCounter=1;
            if(sampleCounter==maxCounter)// maxCounter 为计数器的最大值
            {
                            OutputPin()->Deliver(pSample);// 把该帧发到下游编码 Filter
             sampleCounter=0;// 计数器清零
          }
          sampleCounter++;// 计数器加 1
          return S_OK;
}}
加了帧率控制 Filter 的发送端 Filter Graph 如图 4 所示:
 
图4    实现了帧率控制的Filter Graph 
4 总结
该系统采用了 DirectShow 技术实现了 MPEG-4 视频数据的传输,视频数据的传输采用了 RTP 协议。而且还实现了远端帧率的控制,该系统可以很方便的移植到未来 3G 网络的图像传输系统中。对编解码器进行研究,采用 H.264 技术实现编解码 Filter 是下一步要完成的工作,当然在传输质量( QoS )方面也要深入进行研究。
参考文献
邵林 , 曹汉强 . 基于 DiectShow 的视频广播系统设计与实现 [J]. 微型机与应用 ,2004, 4 :58-60
2 Microsoft DirectX C++ SDK Document [EB/OL],2003
陆其明 . DiectShow 开发指南 [M]. 北京 . 清华大学出版社 ,2004
陆其明 . DiectShow 实务精选 [M]. 北京 : 科学出版社 ,2004
张明华 . 《基于 RTP 的视频传输控制方法的研究》 [D]. 郑州市:郑州大学 , 2004.3
6 Jori Liesenborgs   JRTPLIB 3.1.0 [EB/OL]
http://research.edm.luc.ac.be/jori/jrtplib/jrtplib.pdf
 
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值