




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
用DirectShow实现QQ的音视频聊天功能 当下比较流行的即时通信工具,比如MSN,QQ等都实现了视音频的功能,通过视频,音频,我们可以更好的和朋友通过网络进行沟通,本文通过DirectShow技术模拟QQ实现了视频和音频的采集,传输,基本实现了QQ的视音频聊天的功能。 网络视音频系统主要功能就在于视音频的采集,网络传输两个方面,通过Video Capture系列API函数,你就可以轻松的搞定视频捕捉,但是对于视频的网络传输,则要费一番功夫了。 对于视音频数据的传输,只简单地使用数据报套接字传输音视频数据是不可行的,还必须在UDP层上采用RTP(实时传输协议)和RTCP(实时传输控制协议)来改善服务质量。实时传输协议提供具有实时特征的、端到端的数据传输服务。我们在音视频数据前插入包含有载荷标识、序号、时间戳和同步源标识符的RTP包头,然后利用数据报套接字在IP网络上传输RTP包,以此改善连续重放效果和音视频同步。实时传输控制协议RTCP用于RTP的控制,它最基本的功能是利用发送者报告和接收者报告来推断网络的服务质量,若拥塞状况严重,则改用低速率编码标准或降低数据传输比特率,以减少网络负荷,提供较好的Q.S保证。Directshow对于音视频的采集提供了很好的接口,利用ICaptureGraphBuilder2接口可以很轻松的建立起视频捕捉的graph图,通过枚举音频设备Filter,也可以很轻松的实现音频的捕捉,有点麻烦的是音视频数据的传输,我们可以自己封装RTP和RTCP的协议,来自己实现一个filter,用来发送和接收音视频数据,当然了Directshow也提供了一组支持使用RTP协议的网络传输多媒体流的Filters。你也完全可以用Directshow提供的RTP系列的filter实现数据的传输。下面分析一下这些RTP Filters。新定义的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是没有问题的。RTP Source filter被用来从一个单独的RTP会话中接收RTP和RTCP包。这个filter提供一个指定发送给其它主机RTCP接收器报告和指定网络地址和端口接口来接收RTP会话的接口。RTP Rend filter是用来将数据发到网络上的一个filter,这个filter也提供了和RTP source Filter 类似的接口。RTP Demux filter用来多路分离来自 RTP Source filter的RTP 包,这个filter有一个或者多个输出的pin。这个Filter提供了如何控制多路分离和如何分配到特定输出pin的接口。RTP RPH Filter 是用来网络过来的RTP包还原成原来的数据格式,主要支持H.261,H.263,Indeo,G.711,G.723和G.729和常见的多种音视频负载类型。RTP SPH filter则和RPH filter的功能相对,它的任务是将音视频 压缩filter输出的 数据分解为RTP包,它提供的接口有指定最大生成包大小和pt值。下面我们看看如何用这些filter来搭建我们采集和传输的graph图。图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。有了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之中。图3 网络视频和音频交互的Graph图如果你也想自己封装自己的Source 和Render filter,首先你要选择自己的编解码,视频编解码是选择H261,H263,还是 MEPG4,音频是选择G729还是G711,要首先确定好。选好编解码,封装的工作就简单了。不多说了,下面看看我给出的代码吧。首先要定义一下用到的四个RTP filter的CLSID。static const GUID CLSID_FG729Render = 0x3556f7d8, 0x5b5, 0x4015, 0xb9, 0x40, 0x65, 0xb8, 0x8, 0x94, 0xc8, 0xf9 ; /音频发送 static const GUID CLSID_FG729Source = 0x290bf11a, 0x93b4, 0x4662, 0xb1, 0xa3, 0xa, 0x53, 0x51, 0xeb, 0xe5, 0x8e ;/音频接收static const GUID CLSID_FH263Source = 0xa0431ccf, 0x75db, 0x463e, 0xb1, 0xcd, 0xe, 0x9d, 0xb6, 0x67, 0xba, 0x72 ;/视频接收static const GUID CLSID_FH263Render = 0x787969cf, 0xc1b6, 0x41c5, 0xba, 0xa8, 0x4e, 0xff, 0xa3, 0xdb, 0xe4, 0x1f ;/视频发送/发送和接收音视频数据的filterCComPtr m_pAudioRtpRender ;CComPtr m_pAudioRtpSource ;CComPtr m_pVideoRtpRender ;CComPtr m_pVideoRtpSource ;char szClientA100;int iVideoPort = 9937;int iAudioPort = 9938;/构建视频的graph图,并发送数据CComPtr m_pVideoGraphBuilder; /视频图形管理器 CComPtr m_pVideoCapGraphBuilder; CComPtr m_pFilterVideoCap;CComPtr m_pVideoWindow;CComPtr m_pVideoMediaCtrl ;CComPtr m_pVideoRenderFilter;HRESULT CMyDialog:VideoGraphInitAndSend()HRESULT hr;hr =m_pVideoGraphBuilder.CoCreateInstance( CLSID_FilterGraph );if(FAILED(hr)return hr;hr =m_pVideoCapGraphBuilder.CoCreateInstance( CLSID_CaptureGraphBuilder2);if(FAILED (hr)return hr;m_pVideoCapGraphBuilder-SetFiltergraph(m_pVideoGraphBuilder);m_pVideoGraphBuilder-QueryInterface(IID_IMediaControl, (void *)&m_pVideoMediaCtrl);m_pVideoGraphBuilder-QueryInterface(IID_IVideoWindow,(void*)&m_pVideoWindow)FindDeviceFilter(&m_pFilterVideoCap,CLSID_VideoInputDeviceCategory);if(m_pFilterVideoCap)m_pVideoGraphBuilder-AddFilter( m_pFilterVideoCap,T2W(VideoCap) ) ;/创建预览的filterhr = m_pRenderFilterVideo.CoCreateInstance(CLSID_VideoRenderer);if(FAILED(hr)return hr;m_pVideoGraphBuilder-AddFilter( m_pRenderFilterVideo, LVideoRenderFilter );Connect(m_pFilterVideoCap ,m_pRenderFilterVideo) ;/设置预览的窗口CRect rc ; GetClientRect(m_hOwnerWnd, &rc );int iWidth = rc.right - rc.left ;int iHeight = rc.bottom - rc.top ;int iLeft, iTop;if(iHeight*1.0)/(iWidth*1.0) = 0.75)/按宽度算int tmpiHeight = iWidth*3/4;iTop = (iHeight - tmpiHeight)/2;iHeight = tmpiHeight;iLeft = 0;else/按高度算int tmpiWidth = iHeight*4/3;iLeft = (iWidth - tmpiWidth)/2;iWidth = tmpiWidth;iTop = 0; m_pVideoWindow-put_Owner( (OAHWND) m_hPreviewWnd ) ;m_pVideoWindow-put_Visible( OATRUE );m_pVideoWindow-put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS ) ;/连接到网络并发送CComPtr pRenderOption; CComPtr pVideoOption;tagVideoInfo vif(160,120,24);int t=(int)(m_iFrameRate/5)*5)+5;vif.nBitCount=24;vif.nWidth=160;vif.nHeight=120;hr = :CoCreateInstance(CLSID_FH263Render, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void *)&m_pVideoRtpRender);if(FAILED(hr)return hr;m_pVideoRtpRender-QueryInterface(IID_IJRTPOption, (void*)&pRenderOption);m_pVideoRtpRender-QueryInterface(IID_IVideoOption,(void*)&pVideoOption); pVideoOption-SetProperty(&vif);pVideoOption-SetSendFrameRate(m_iFrameRate,1);/1 不发送数据,0 实际发送数据Connect(m_pFilterVideoCap ,m_pVideoRtpRender) ;/连接对方hr= pRenderOption-Connect(szClientA,iVideoPort,1024);if(FAILED(hr)return hr;m_pVideoMediaCtrl-Run();/视频的接收CComPtr m_pVideoGraphBuilder; /视频图形管理器 CComPtr m_pFilterVideoCap;CComPtr m_pVideoWindow;CComPtr m_pVideoMediaCtrl ;CComPtr m_pVideoRenderFilter;HWND m_hRenderWnd ;HRESULT VideoRecive()HRESULT hr;hr=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IFilterGraph,(void*)&m_pVideoGraphBuilder);m_pVideoGraphBuilder-QueryInterface(IID_IMediaControl, (void *)&m_pVideoMediaCtrl);m_pVideoGraphBuilder-QueryInterface(IID_IVideoWindow,(void*)&m_pVideoWindow)hr = :CoCreateInstance(CLSID_FH263Source, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void *)&m_pVideoRtpSource);if(FAILED(hr)return hr;m_pVideoGraphBuilder-AddFilter(m_pVideoRtpSource, LMy Custom Source);CComPtr m_pRtpOption; CComPtr m_pVideoOption;m_pVideoRtpSource-QueryInterface(IID_IJRTPOption, (void *)&m_pRtpOption);m_pVideoRtpSource-QueryInterface(IID_IVideoOption, (void *)&m_pVideoOption);tagVideoInfo vif(160, 120 ,24);m_pVideoOption-SetProperty(&vif);hr= pRenderOption-Connect(szClientA,iVideoPort +1,1024);if(FAILED(hr)return hr;/创建预览的filterhr = m_pRenderFilterVideo.CoCreateInstance(CLSID_VideoRenderer);if(FAILED(hr)return hr;m_pVideoGraphBuilder-AddFilter( m_pRenderFilterVideo, LVideoRenderFilter );Connect(m_pVideoRtpSource ,m_pRenderFilterVideo) ; CRect rc ; GetClientRect(m_hOwnerWnd, &rc );int iWidth = rc.right - rc.left ;int iHeight = rc.bottom - rc.top ;int iLeft, iTop;if(iHeight*1.0)/(iWidth*1.0) = 0.75)/按宽度算int tmpiHeight = iWidth*3/4;iTop = (iHeight - tmpiHeight)/2;iHeight = tmpiHeight;iLeft = 0;else/按高度算int tmpiWidth = iHeight*4/3;iLeft = (iWidth - tmpiWidth)/2;iWidth = tmpiWidth;iTop = 0; m_pVideoWindow-put_Owner( (OAHWND) m_hRenderWnd ) ;m_pVideoWindow-put_Visible( OATRUE );m_pVideoWindow-put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS ) ; m_pVideoMediaCtrl-Run();return S_OK;/HRESULT FindDeviceFilter(IBaseFilter * ppSrcFilter,GUID deviceGUID)HRESULT hr;IBaseFilter * pSrc = NULL;CComPtr pMoniker =NULL;ULONG cFetched;if (!ppSrcFilter)return E_POINTER;/ Create the system device enumeratorCComPtr pDevEnum =NULL;hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,IID_ICreateDevEnum, (void *) &pDevEnum);if (FAILED(hr)return hr;/ Create an enumerator for the video capture devicesCComPtr pClassEnum = NULL;hr = pDevEnum-CreateClassEnumerator (deviceGUID, &pClassEnum, 0);if (FAILED(hr)return hr;if (pClassEnum = NULL)return E_FAIL;if (S_OK = (pClassEnum-Next (1, &pMoniker, &cFetched)hr = pMoniker-BindToObject(0,0,IID_IBaseFilter, (void*)&pSrc);if (FAILED(hr)return hr;elsereturn E_FAIL;*ppSrcFilter = pSrc;return S_OK;/构建音频Graph图,并发送CComPtr m_pAudioGraphBuilder; /音频图形管理器 CComPtr m_pCapAudioGraphBuilder; CComPtr m_pFilterAudioCap;CComPtr m_pAudioMediaCtrl ;HRESULT AudioGraphInit()HRESULT hr;hr =m_pAudioGraphBuilder.CoCreateInstance( CLSID_FilterGraph );if(FAILED(hr)return hr;hr =m_pCapAudioGraphBuilder.CoCreateInstance( CLSID_CaptureGraphBuilder2);if(FAILED (hr)return hr;m_pAudioGraphBuilder-SetFiltergraph(m_pCapAudioGraphBuilder);m_pAudioGraphBuilder-QueryInterface(IID_IMediaControl, (void *)&m_pAudioMediaCtrl);FindDeviceFilter(&m_pFilterVideoCap,CLSID_AudioInputDeviceCategory);if(m_pFilterAudioCap)m_pAudioGraphBuilder-AddFilter( m_pFilterAudioCap,T2W(AudioCap) ) ;/发送到网络hr =:CoCreateInstance(CLSID_FG729Render,NULL,CLSCTX_INPROC,IID_IBaseFilter,(void*)&m_pFilterRtpSendAudio)if(FAILED(hr)return hr;m_pAudioGraphBuilder-AddFilter(m_pAudioRtpRender, LFilterRtpSendAudio);Connect(m_pFilterAudioCap,m_pAudioRtpRender);CComPtr pOption ;m_pAudioRtpRender-QueryInterface(IID_IJRTPOption,(void*)&pOption)hr =pOption-Conn
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 19023-2025质量管理体系成文信息指南
- JJG(烟草)27-2010烟草加工在线红外测温仪检定规程
- 2025年英语口语测试全真模拟试卷:多邻国英语测试(DET)情景描述与观点表达策略
- 考研复习-风景园林基础考研试题【培优b卷】附答案详解
- 风景园林基础考研资料试题及答案详解(名校卷)
- 《风景园林招投标与概预算》试题A附参考答案详解【达标题】
- 2025年黑龙江省五常市辅警招聘考试试题题库含答案详解
- 2024年湖南化工职业技术学院单招职业技能测试题库及答案解析 (一)
- 6.1.2呼吸机的发展16世纪人工通气安烈德医生在动物的气
- 2025年Z世代消费趋势分析:新消费品牌品牌形象塑造策略报告
- 2025年金融科技应用考试试题及答案
- 2025年全球科技:中国无人驾驶出租车市场:商业化之路研究报告(英文版)-高盛
- 2025南京租房合同协议范本下载
- 农业光伏电站项目投资估算
- 家具供货结算协议书
- 2025年公证员资格考试全国范围真题及答案
- 高考前2天校长在出征仪式生动员讲话与在座的大家分享了3颗心
- 游客自愿离团协议书
- 2025重庆市潼南区梓潼街道社区工作者考试真题
- 2025年中式烹调师(高级)考试试题题库
- 热射病护理试题及答案
评论
0/150
提交评论