mediastreamer2是一个功能强大且小巧的流引擎,专门为视频电话应用而开发的。为linphone中所有的接收、发送多媒体流提供处理,包括音频视频捕捉、编码、解码、渲染。
Filter: 媒体库中处理数据的组件。一个filter有0到数个输入流和0到数个输出流。
filter的作用:在mediastreamer2里面是MSFilter,可以利用MSFilter实现下面的应用,实例参见/mediastreamer2/tests/:
捕获音频或者视频数据.、播放音频或者显示视频数据.、发送或者接受RTP数据.、对音频或者视频数据的编解码、变化 (视频大小调整, 音频取样等等) 数据、 复制数据.、混和音频视频数据.
graph的作用:是管理几个连接在一起的filter的组件. 它能够把数据从输出流传输到输入流 并且负责管理这些filters
最简单的graph 例子:AUDIO CAPTURE (FILTER) --> ENCODE (FILTER) --> RTP(FILTER)
上面的graph 由三个 filters组成. Audio capture filter没有输入,直接从驱动捕获音频数据然后提供给输出流. 然后把输出流连接到encoder filter 的输入流上,coder filter 把这些音频数据进行编码以后然后送给输出流.最后把这个输出流连接到rtp filter的输入流上,然后由rtp filter把数据封装成rtp送出去。
该模块的设计可以让应用开发者使用自己的encode/decode filter 替代已有的"encode/decode filter" . 该媒体库支持g711u, g711a, h263的encode filter. 应用开发者也可以动态加入自己实现的encode filter,用来支持其他的编码格式。
如何使用媒体库?
媒体库提供许多功能, 它主要用来管理RTP 音频和视频 会话.你将需要使用API函数创建filters,并且把它们连接进一个graph. 然后使用API函数能够用来启动和停止graph.
媒体库的初始化
要使用媒体库, 首先需要对他进行初始化:
ms_init();
媒体库提供许多filters. 这些filter必须被连接在一起以至一个filter的输出能够变成其他filter的输入.
通常, filters 被用来处理音频和视频数据. 他们能够捕获音频和视频数据,播放音频和视频数据, 对这些数据进行编解码, 合成这些数据 , 转换这些数据.最重要的filters 是RTP filters,他能够接收和发送RTP数据.
Graph的例子
要真正使用媒体库进行通话, 就必须构建两个graphs. 当然这两个graph都相当简单。
第一个graph需要三个filter,从声卡捕获数据,然后进行编码,最后把编码后的数据发送给RTP session.
AUDIO -> ENCODER -> RTP
CAPTURE -> -> SENDER
第二个graph同样需要三个filter, 从一个RTP session接收数据,然后解码,最后把解码后的数据发送给播放设备.
RTP -> DECODER -> AUDIO
RECEIVER -> -> PLAYBACK
初始化Graph的例子
为了便于阅读和理解,下面的代码没有差错检查.为了构造一个graph, 需要一些而外的输入输出设备:比如需要选择一个声卡用来捕获和播放音频,同时还需要使用创建一个RTP session用来发送和接受rtp流.
MSSndCard *sndcard;
sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
/* audio capture filter */
MSFilter *soundread=ms_snd_card_create_reader(captcard);
MSFilter *soundwrite=ms_snd_card_create_writer(playcard);
MSFilter *encoder=ms_filter_create_encoder("PCMU");
MSFilter *decoder=ms_filter_create_decoder("PCMU");
MSFilter *rtpsend=ms_filter_new(MS_RTP_SEND_ID);
MSFilter *rtprecv=ms_filter_new(MS_RTP_RECV_ID);
RtpSession *rtp_session = *** your_ortp_session *** ;
ms_filter_call_method(rtpsend,MS_RTP_SEND_SET_SESSION,rtp_session);
ms_filter_call_method(rtprecv,MS_RTP_RECV_SET_SESSION,rtp_session);
MSFilter *dtmfgen=ms_filter_new(MS_DTMF_GEN_ID);
大多数情况下上面的graph还是不够的: 通常还需要对filter进行一些配置. ,比如还需要设置声卡filters的取样率。
int sr = 8000;
int chan=1;
ms_filter_call_method(soundread,MS_FILTER_SET_SAMPLE_RATE,&sr);
ms_filter_call_method(soundwrite,MS_FILTER_SET_SAMPLE_RATE,&sr);
ms_filter_call_method(stream->encoder,MS_FILTER_SET_SAMPLE_RATE,&sr);
ms_filter_call_method(stream->decoder,MS_FILTER_SET_SAMPLE_RATE,&sr);
ms_filter_call_method(soundwrite,MS_FILTER_SET_NCHANNELS, &chan);
/* if you have some fmtp parameters (from SDP for example!)
char *fmtp1 = ** get your fmtp line **;
char *fmtp2 = ** get your fmtp line **;
ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP, (void*)fmtp1);
ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)fmtp2);
链接filters并且运行graph 的例子
ms_filter_link(stream->soundread,0,stream->encoder,0);
ms_filter_link(stream->encoder,0,stream->rtpsend,0);
ms_filter_link(stream->rtprecv,0,stream->decoder,0);
ms_filter_link(stream->decoder,0,stream->dtmfgen,0);
ms_filter_link(stream->dtmfgen,0,stream->soundwrite,0);
按照上面的步骤链接后,还需要把这些filters配属给一个ticker. Ticker 是graph管理器,负责启动filters.
上面的例子里有两个graph, 我们需要把两个graph中没有输入流的filter配属给Ticker.
/* create ticker */
MSTicker *ticker=ms_ticker_new();
ms_ticker_attach(ticker,soundread);
ms_ticker_attach(ticker,rtprecv);
解除filters并且停止graph的例子
ms_ticker_detach(ticker,soundread);
ms_ticker_detach(ticker,rtprecv);
ms_filter_unlink(stream->soundread,0,stream->encoder,0);
ms_filter_unlink(stream->encoder,0,stream->rtpsend,0);
ms_filter_unlink(stream->rtprecv,0,stream->decoder,0);
ms_filter_unlink(stream->decoder,0,stream->dtmfgen,0);
ms_filter_unlink(stream->dtmfgen,0,stream->soundwrite,0);
if (rtp_session!=NULL) rtp_session_destroy(rtp_session);
if (rtpsend!=NULL) ms_filter_destroy(rtpsend);
if (rtprecv!=NULL) ms_filter_destroy(rtprecv);
if (soundread!=NULL) ms_filter_destroy(soundread);
if (soundwrite!=NULL) ms_filter_destroy(soundwrite);
if (encoder!=NULL) ms_filter_destroy(encoder);
if (decoder!=NULL) ms_filter_destroy(decoder);
if (dtmfgen!=NULL) ms_filter_destroy(dtmfgen);
if (ticker!=NULL) ms_ticker_destroy(ticker);