版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
用DirectShow实现QQ的音视频聊天功能开发者在线B更新时间:2007-10-作者:智慧的鱼来源:天极网
本文关键词:DirectShowQQ音视频聊天当下比较流行的即时通信工具,比如MSN,QQ等都实现了视音频的功能,通过视频,音频,我们可以更好的和朋友通过网络进行沟通,本文通过DirectShow技术模拟QQ实现了视频和音频的采集,传输,基本实现了QQ的视音频聊天的功能。网络视音频系统主要功能就在于视音频的采集,网络传输两个方面,通过VideoCapture系列API函数,你就可以轻松的搞定视频捕捉,但是对于视频的网络传输,则要费一番功夫了。对于视音频数据的传输,只简单地使用数据报套接字传输音视频数据是不可行的,还必须在UDP层上采用RTP(实时传输协议)和RTCP(实时传输控制协议)来改善服务质量。实时传输协议提供具有实时特征的、端到端的数据传输服务。我们在音视频数据前插入包含有载荷标识、序号、时间戳和同步源标识符的RTP包头,然后利用数据报套接字在IP网络上传输RTP包,以此改善连续重放效果和音视频同步。实时传输控制协议RTCP用于RTP的控制,它最基本的功能是利用发送者报告和接收者报告来推断网络的服务质量,若拥塞状况严重,则改用低速率编码标准或降低数据传输比特率,以减少网络负荷,提供较好的Q.S保证。Directshow对于音视频的采集提供了很好的接口,利用ICaptureGraphBuilder2接口可以很轻松的建立起视频捕捉的graph图,通过枚举音频设备Filter,也可以很轻松的实现音频的捕捉,有点麻烦的是音视频数据的传输,我们可以自己封装RTP和RTCP的协议,来自己实现一个filter,用来发送和接收音视频数据,当然了Directshow也提供了一组支持使用RTP协议的网络传输多媒体流的Filters。你也完全可以用Directshow提供的RTP系列的filter实现数据的传输。下面分析一下这些RTPFilters。新定义的Filter包括RTPSourceFilter,RTPRenderFilter,RTPDemuxFilter,RTPReceivePlayloadHandler(RPH)filter,RTPSendPayload(SPH)filter,使用这5个filter构建一个通过RTP协议传输音视频数据的Graph是没有问题的。RTPSourcefilter被用来从一个单独的RTP会话中接收RTP和RTCP包。这个filter提供一个指定发送给其它主机RTCP接收器报告和指定网络地址和端口接口来接收RTP会话的接口。RTPRendfilter是用来将数据发到网络上的一个filter,这个filter也提供了和RTPsourceFilter类似的接口。RTPDemuxfilter用来多路分离来自RTPSourcefilter的RTP包,这个filter有一个或者多个输出的pin。这个Filter提供了如何控制多路分离和如何分配到特定输出pin的接口。RTPRPHFilter是用来网络过来的RTP包还原成原来的数据格式,主要支持H.261,H.263,Indeo,G.711,G.723和G.729和常见的多种音视频负载类型。RTPSPHfilter则和RPHfilter的功能相对,它的任务是将音视频压缩filter输出的数据分解为RTP包,它提供的接口有指定最大生成包大小和pt值。
下面我们看看如何用这些filter来搭建我们采集和传输的graph图。图1和图2展示了DirectShowRTP中定义的filters如何运用。图1是一个采集本地多媒体数据并使用RTP协议通过网络发送的filtergraph。它包含一个输出原始视频帧的视频采集filter,紧跟一个压缩帧的编码filter。一旦压缩,这些帧就会被发送到RTPSPHfilter,分片打包,生成RTP包,对应的发送到RTPRenderfilter,通过网络传输这些包。图2展现了一个filtergraph,用来接收包含视频流RTP包,播放视频。这个graph由一个用来接收包的RTPSourcefilter,一个根据源和负载类型进行分类的RTPDemuxfilter,一个把RTP包转为压缩视频帧的RTPRPHfilter组成。这些filter随后的是用来解压帧的解码filter,一个显示未压缩帧的渲染filter。有了RTPfilter的帮助我们就可以完成类似qq的功能了,可以实现在网络上进行视频和音频的交互了,下面我给出在网络上两个客户端A和B进行音频和视频交互的Graph图。这里我对图1和图2中的RTPfilter进行了自己封装,将编解码filter直接封装到了RTPSourcefilter和RTPRenderfilter中,这样Graph图就显得很简洁,RTPSourcefilter只是用来接收网络过来的音视频数据,然后将数据传递给客户程序,RTPRenderfilter则是将采集到的音视频数据发送到网络上的另一个客户端,编解码则的工作则封装到这两个filter之中。图3网络视频和音频交互的Graph图如果你也想自己封装自己的Source和Renderfilter,首先你要选择自己的编解码,视频编解码是选择H261,H263,还是MEPG4,音频是选择G729还是G711,要首先确定好。选好编解码,封装的工作就简单了。不多说了,下面看看我给出的代码吧。首先要定义一下用到的四个RTPfilter的CLSID。staticconstGUIDCLSID_FG729Render={0x3556f7d8,0x5b5,0x4015,{0xb9,0x40,0x65,0xb8,0x8,0x94,0xc8,0xf9}};〃音频发送staticconstGUIDCLSID_FG729Source={0x290bf11a,0x93b4,0x4662,{0xb1,0xa3,0xa,0x53,0x51,0xeb,0xe5,0x8e}};〃音频接收staticconstGUIDCLSID_FH263Source={0xa0431ccf,0x75db,0x463e,{0xb1,0xcd,0xe,0x9d,0xb6,0x67,0xba,0x72}};〃视频接收staticconstGUIDCLSID_FH263Render={0x787969cf,0xc1b6,0x41c5,{0xba,0xa8,0x4e,0xff,0xa3,0xdb,0xe4,0x1f}};〃视频发送〃发送和接收音视频数据的filterCComPtr<IBaseFilter>m_pAudioRtpRender;CComPtr<IBaseFilter>m_pAudioRtpSource;CComPtr<IBaseFilter>m_pVideoRtpRender;CComPtr<IBaseFilter>m_pVideoRtpSource;charszClientA[100];intiVideoPort=9937;intiAudioPort=9938;〃构建视频的graph图,并发送数据CComPtr<IGraphBuilder>m_pVideoGraphBuilder;〃视频图形管理器CComPtr<ICaptureGraphBuilder2>m_pVideoCapGraphBuilder;CComPtr<IBaseFilter>m_pFilterVideoCap;CComPtr<IVideoWindow>m_pVideoWindow;CComPtr<IMediaControl>m_pVideoMediaCtrl;CComPtr<IBaseFilter>m_pVideoRenderFilter;HRESULTCMyDialog::VideoGraphInitAndSend(){HRESULThr;hr=m_pVideoGraphBuilder.CoCreatelnstance(CLSID_FilterGraph);if(FAILED(hr))returnhr;hr=m_pVideoCapGraphBuilder.CoCreatelnstance(CLSID_CaptureGraphBuilder2);if(FAILED(hr))returnhr;m_pVideoCapGraphBuilder->SetFiltergraph(m_pVideoGraphBuilder);m_pVideoGraphBuilder->QueryInterface(IID_IMediaControl,(void**)&m_pVideoMediaCtrl);m_pVideoGraphBuilder->Querylnterface(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))returnhr;m_pVideoGraphBuilder->AddFilter(m_pRenderFilterVideo,L"VideoRenderFilter");Connect(m_pFilterVideoCap,m_pRenderFilterVideo);〃设置预览的窗口CRectrc;GetClientRect(m_hOwnerWnd,&rc);intiWidth=rc.right-rc.left;intiHeight=rc.bottom-rc.top;intiLeft,iTop;if((iHeight*1.O)/(iWidth*1.O)>=0.75){〃按宽度算inttmpiHeight=iWidth*3/4;iTop=(iHeight-tmpiHeight)/2;iHeight=tmpiHeight;iLeft=0;}else{〃按高度算inttmpiWidth=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<IRtpOption>pRende「Option;CComPtr<IVideoOption>pVideoOption;tagVideoInfovif(160,120,24);intt=((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))returnhr;m_pVideoRtpRender->QueryInterface(IID_IJRTPOption,(void**)&pRende「Option);m_pVideoRtpRender->Querylnterface(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))returnhr;m_pVideoMediaCtrl->Run();}〃视频的接收CComPtr<IGraphBuilder>m_pVideoGraphBuilder;〃视频图形管理器CComPtr<IBaseFilter>m_pFilterVideoCap;CComPtr<IVideoWindow>m_pVideoWindow;CComPtr<IMediaControl>mpVideoMediaCtrl;CComPtr<IBaseFilter>m_pVideoRenderFilter;HWNDm_hRenderWnd;HRESULTVideoRecive(){HRESULThr;hr=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IFilterGraph,(void**)&m_pVideoGraphBuilder);m_pVideoGraphBuilder->QueryInterface(IID_IMediaControl,(void**)&m_pVideoMediaCtrl);m_pVideoGraphBuilder->Querylnterface(IID_IVideoWindow,(void**)&m_pVideoWindow)hr=::CoCreateInstance(CLSID_FH263Source,NULL,CLSCTX_INPROC,IID_IBaseFilter,(void**)&m_pVideoRtpSource);if(FAILED(hr))returnhr;m_pVideoGraphBuilder->AddFilter(m_pVideoRtpSource,L"MyCustomSource");CComPtr<IRtpOption>m_pRtpOption;CComPtr<IVideoOption>m_pVideoOption;m_pVideoRtpSource->Querylnterface(IID_IJRTPOption,(void**)&m_pRtpOption);m_pVideoRtpSource->Querylnterface(IID_IVideoOption,(void**)&m_pVideoOption);tagVideoInfovif(160,120,24);m_pVideoOption->SetProperty(&vif);hr=pRenderOption->Connect(szClientA,iVideoPort+1,1024);if(FAILED(hr))returnhr;〃创建预览的filterhr=m_pRenderFilterVideo.CoCreateInstance(CLSID_VideoRenderer);if(FAILED(hr))returnhr;m_pVideoGraphBuilder->AddFilter(m_pRenderFilterVideo,L"VideoRenderFilter");Connect(m_pVideoRtpSource,m_pRenderFilterVideo);CRectrc;GetClientRect(m_hOwnerWnd,&rc);intiWidth=rc.right-rc.left;intiHeight=rc.bottom-rc.top;intiLeft,iTop;if((iHeight*1.0)/(iWidth*1.0)>=0.75){〃按宽度算inttmpiHeight=iWidth*3/4;iTop=(iHeight-tmpiHeight)/2;iHeight=tmpiHeight;iLeft=0;}else{〃按高度算inttmpiWidth=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();returnS_OK;}//HRESULTFindDeviceFilter(IBaseFilter**ppSrcFilter,GUIDdeviceGUID){HRESULThr;IBaseFilter*pSrc=NULL;CComPtr<IMoniker>pMoniker=NULL;ULONGcFetched;if(!ppSrcFilter)returnE_POINTER;//CreatethesystemdeviceenumeratorCComPtr<ICreateDevEnum>pDevEnum=NULL;hr=CoCreatelnstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC,IID_ICreateDevEnum,(void**)&pDevEnum);if(FAILED(hr))returnhr;//CreateanenumeratorforthevideocapturedevicesCComPtr<IEnumMoniker>pClassEnum=NULL;hr=pDevEnum->CreateClassEnumerator(deviceGUID,&pClassEnum,0);if(FAILED(hr))returnhr;if(pCIassEnum==NULL)returnE_FAIL;if(S_OK==(pClassEnum->Next(1,&pMoniker,&cFetched))){hr=pMoniker->BindToObject(0,0,IID_IBaseFilter,(void**)&pSrc);if(FAILED(hr))returnhr;}elsereturnE_FAIL;*ppSrcFilter=pSrc;returnS_OK;}〃构建音频Graph图,并发送CComPtr<IGraphBuilder>m_pAudioGraphBuilder;〃音频图形管理器CComPtr<ICaptureGraphBuilder2>m_pCapAudioGraphBuilder;CComPtr<IBaseFilter>m_pFilterAudioCap;CComPtr<IMediaControl>m_pAudioMediaCtrl;HRESULTAudioGraphlnit(){HRESULThr;hr=m_pAudioGraphBuilder.CoCreateInstance(CLSID_FilterGraph);if(FAILED(hr))returnhr;hr=m_pCapAudioGraphBuilder.CoCreatelnstance(CLSID_CaptureGraphBuilder2);if(FAILED(hr))returnhr;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))returnhr;m_pAudioGraphBuilder->AddFilter(m_pAudioRtpRender,L"FilterRtpSendAudio");Connect(m_pFilterAudioCap,m_pAudioRtpRender);CComPtr<IRtpOption>pOption;m_pAudioRtpRender->Querylnterface(IID_IJRTPOption,(void**)&pOption)hr=pOption->Connect(szClientA,iAudioPort,1024);if(FAILED(hr))returnhr;m_pAudioMedia
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 订货合同的履行要点
- 设备品质保证书案例
- 设备采购合同的交货方式
- 设计项目招标文件招标
- 诚信担保书状
- 财务审计与合规性评估
- 购销合同回款期法律规定
- 购销合同的仲裁与诉讼
- 购销资产合同书范本
- 赠送运营服务合同模板
- 政治生日愿望三篇
- 华友钴业行业个股分析
- 期末试卷(试题)-2023-2024学年一年级数学下册人教版
- 护士家长进课堂
- 保洁玻璃清洁培训课件
- 住房保障社工述职报告
- 知识产权维权授权书
- 第23课《孟子》三章《得道多助失道寡助》公开课一等奖创新教学设计统编版语文八年级上册
- 餐厅预防食品异物课件
- 郑州大学801经济学基础(政治经济学、西方经济学)历年考研真题汇编
- 2022年新高考重庆政治试卷真题(解析版)
评论
0/150
提交评论