Mediastream2 用法介绍及简明实例分析

linphone是一个轻量级voip客户端,linphone的架构设计十分的清晰,其底层音视频引擎mediastream2是一个独立的模块,基于它可以很容易的实现各种音视频的应用。

linphone 整体架构介绍

http://www.linphone.org/eng/documentation/dev/

linphone拥有自己的用户接口和核心引擎(音频/视频引擎),允许在相同的函数基础上建立不同的用户接口。

用户接口

GTK+用户接口

命令行接口(linphonec, linphonecsh)

IPhone用户接口(基于objective C)

基于Java实现的Andorid应用

liblinphone,核心引擎:提供了高度容易扩展的函数接口,它是一个功能强大的SIP VoIP video SDK,我们可以基于该框架实现任意的语音/视频应用。

liblinphone基于下列组件实现:

mediastream2,功能强大的音/视多媒体SDK,用于创建和处理音视频流

oRTP,简单的RTP处理库。

eXosip,SIP UA 库,其基于libosip2实现。

linphone和liblinphone都是使用C语言实现的,下面为linphone的整体结构。

Mediastream2实现机制

http://www.linphone.org/eng/documentation/dev/mediastreamer2.html

mediastream2是一个功能强大的,轻量级流处理引擎,特别适合于音视频电话应用方面的开发。它能够完成音视频流的捕获、接收、发送、编码、解码、渲染等功能。

特性:

可以捕获、重放多种基于各种平台音频架构(ALSA, AudioUnits, AudioQueue, WaveApi)。
接收、发送RTP数据包。
支持如下的音视频编解码格式:音频speex, G711, GSM, iLBC, AMR, AMR-WB, G722, SILK, G729; 视频: H263, theora, MPEG4, H264 and VP8.
支持音频的wav格式文件的读取和保存。
捕获摄像头的YUV图片格式(基于平台独立的API)。
优化,渲染YUV图片。
立体声输出。
自定义声音侦测。
回声消除,基于speex库 和Android上的webrtc AEC机制。
支持音频会议。
支持音频参数均衡。
音量控制,自动增益控制。
具有IEC NAT穿越动能。
自适应比特率控制算法:根据接收的RTCP反馈信息自动适应编码速率。

mediastream2以扩展插件的形式支持H264, ILBC, SILK, AMR, AMR-WB and G729。

设计和原理:

mediastream2中每一个处理实体都包含一个MSFilter结构,每一个MSFiter有一个或者若干个输入和输出,通过这些输入和输出可以将各个MSFilter连接起来。

下面为一个简单的例子:

MSRtpRecv:接收网络上的数据包,解包后将它们输出到下一个MSFilter。
MSSpeexDec:接收输入的音频数据包(假设音频用speex编码),解码并输出到下一个MSFilter。
MSFileRec:接收输入的语音数据并保存为wav格式文件(假设输入为16bit 线性 PCM)。

MSFilter可以被串接成一个filter链,我们接收网络上的RTP包,然后解码并保存成一个wav文件。

MSRtpRecv –> MSSpeexDec –> MSFileRec

媒体处理中的调度对象为MSTicker,它一个独立的线程,其每10ms被唤醒一次,然后它会处理他所管理的媒体链的数据。几个MSTicker可以同时运行,例如,一个负责处理音频,一个负责处理视频,或在不同的处理器中运行不同的MSTicker。

以上是Linphone官方网站上的介绍,下面我们实现一个本地录音机实例来具体说明MSFilter到底是如何工作的。

本地录音机的实现

1.Filter的分类和定义:

从源码目录我们可以看到Filter大概分为以下几种,音频,视频和其他。

音频Filter:

├── aac-eld.c

├── alaw.c ITU-G.711 alaw encoder & decoder

├── ulaw.c ITU-G.711 ulaw encoder & decoder

├── l16.c L16 dummy encoder & decoder

├── msg722.c G.722 wideband encoder & decoder

├── msopus.c opus encoder & decoder

├── msspeex.c speex encoder & decoder

├── gsm.c GSM encoder & decoder

├── oss.c Sound playback & playback filter for OSS drivers

├── alsa.c Sound playback & playback filter ALSA Driver

├── macsnd.c Sound playback & playback filter for OSX Audio Unit

├── arts.c Sound playback & playback filter aRts Driver

├── pasnd.c Sound playback & playback filter Port Audio

├── winsnd.c Sound playback & playback for Windows Sound drivers

├── aqsnd.c Sound playback & playback for OSX AudioQueueService

├── pulseaudio.c Sound input & output plugin based on PulseAudio

├── audiomixer.c A filter that mixes down 16 bit sample audio streams

├── chanadapt.c A filter that converts from mono to stereo and vice versa

├── dtmfgen.c DTMF generator

├── equalizer.c Parametric sound equalizer

├── genericplc.c Generic PLC

├── msconf.c A filter to make conferencing

├── msfileplayer.c Raw files and wav reader

├── msfilerec.c Wav file recorder

├── msresample.c Audio resampler

├── msvolume.c A filter that controls and measure sound volume

├── tonedetector.c Custom tone detection filter

├── speexec.c Echo canceller using speex library(回声消除)

├── webrtc_aec.c Echo canceller using WebRTC library(回声消除)

视频Filter:

├── h264dec.c H264 decoder

├── videodec.c H.263 ,MPEG4 ,MJEPG ,snow decoder

├── videoenc.c H.263 ,MPEG4 ,MJEPG ,snow encoder

├── theora.c theora encoder & decoder

├── vp8.c VP8 encoder & decoder

├── drawdib-display.c A video display based on windows DrawDib api

├── extdisplay.c A display filter sending the buffers to draw to the upper layer

├── x11video.c A video display using X11+Xv

├── glxvideo.c A video display using GL (glx)

├── videoout.c A SDL-based video display

├── jpegwriter.c Take a video snapshot as jpg file

├── mire.c outputs synthetic moving picture

├── nowebcam.c A filter that outputs a static image.

├── pixconv.c A pixel format converter

├── sizeconv.c a small video size converter

├── wincevideods.c A video4windows compatible source filter to stream pictures

├── msv4l2.c A filter to grab pictures from Video4Linux2-powered cameras

├── msv4l.c A video4linux compatible source filter to stream pictures

├── winvideo2.c A video for windows (vfw.h) based source filter to grab pictures

├── winvideo.c A video4windows compatible source filter to stream pictures

├── winvideods.c A video4windows compatible source filter to stream pictures

其他Filter:

├── msrtp.c RTP input & ouput

├── tee.c Reads from input and copy to its multiple outputs

├── join.c Send several inputs to one output

├── itc.c Inter ticker communication

└── void.c Trashes its input (useful for terminating some graphs)

核心组件

├── eventqueue.c 事件队列

├── mscommon.c 初始化等

├── msfilter.c Filter定义

├── msqueue.c 队列结构

├── mssndcard.c 声卡处理

├── msticker.c 定时器

├── mswebcam.c 摄像头处理

└── mtu.c MTU

每个Filter都定义有一个描述信息,所有Filter的描述在ms_base_filter_descs[]和ms_voip_filter_descs[]两个数组中定义,下面以Tee Filter为例说明,后面我们会用到。

我们可以根据ID或者描述构造一个Filter对象,如:

MSFilter *tee=ms_filter_new(MS_TEE_ID);

要回收此对象,如:

ms_filter_destroy(tee);

或者调用此对象的某种方法,如:

ms_filter_call_method(tee,MS_TEE_UNMUTE,&pin);

方法都是在上面tee_methods数组中定义的,如Tee只有两种方法

static MSFilterMethod tee_methods[]={

   {     MS_TEE_MUTE  ,      tee_mute     },

   {     MS_TEE_UNMUTE    ,tee_unmute       },

   {     0     ,      NULL            }

};

tee_init 在构造对象时执行一次,tee_uninit在回收时执行一次,tee_process在每次调度时执行。

2.声卡的管理和使用

声卡的处理在核心组件mssndcard.c中统一管理和使用。

在文件中的开头定义了声卡的全局管理句柄,在库初始化时会把所有可用的声卡挂载到这个链表上。

static MSSndCardManager *scm=NULL;

struct _MSSndCardManager{

              MSList *cards;

              MSList *descs;

};

和Filter类似,每种声卡也有一个描述信息,所有声卡的描述在ms_snd_card_descs[] 数组中定义,相当一个容器:

ms_init() 函数在初始化库的时候依次注册ms_snd_card_manager_register_desc列表中支持的驱动,执行相应的etect函数侦测声卡,然后构造声卡对象并调用对象的Init函数;

当我们需要一个采集或者回放的Filter时,可以直接调用:

MSSndCard *card_capture =ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get());

ms_snd_card_manager_get() 返回一个全局的声卡管理句柄,

ms_snd_card_manager_get_default_capture_card() 扫描全局的管理句柄中注册的声卡设备,并返回第一个可用的声卡对象。

继续调用声卡对象的CreateReader方法,可以得到的声音采集的MSFilte对象。

MSFilter *filte_capture=ms_snd_card_create_reader(card_capture);

3.设计Filter链

现在我们来设计我们的Filter链,有些文档叫Graph.

总共需要4个Filter,采集,复制,保存和回放,Tee Filter在上文已经简单了解过了,他可以把一份数据拷贝到多出。

要使用Filter要先进行mediastream2 和oRTP的初始化,mediastream2库依赖于oRTP库,先初始化oRTP库:

ortp_init();

然后初始化mediastream2库:

ms_init();

我们先简单看一下,他的初始化都大概做了些什么?

ms_base_filter_descs[]和ms_voip_filter_descs[]数组上面提到过,定义了所有的Filter,ms_snd_card_descs[]上面也提到过,定义了所有的声卡驱动,此处就是把所有的定义注册到系统中,摄像头的管理和使用方式其实和声卡是类似的,在后面的视频流实例中我们会用到。最后是加载插件,像我们后面要用到的H.264编码器,在程序中是没有的,前面提到过,是以插件的形式提供的,其实就是动态库的形式。所有的东西都注册完毕,我们就可以创建我们要用的Filter了。

1.创建Filter

MSSndCard *card_capture= ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get());

MSSndCard *card_playback= ms_snd_card_manager_get_default_playback_card(ms_snd_card_manager_get());

MSFilter *capture=ms_snd_card_create_reader(card_capture);

MSFilter *playback=ms_snd_card_create_writer(card_playback);

MSFilter *tee=ms_filter_new(MS_TEE_ID);

MSFilter *rec=ms_filter_new(MS_FILE_REC_ID);

2.设置Filter

int rate=48000;

ms_filter_call_method (capture, MS_FILTER_SET_SAMPLE_RATE,&rate);

ms_filter_call_method (playback, MS_FILTER_SET_SAMPLE_RATE,&rate);

ms_filter_call_method (rec,MS_FILTER_SET_SAMPLE_RATE, &rate);

ms_filter_call_method(rec,MS_FILE_REC_OPEN,”test.wav”);

ms_filter_call_method_noarg(rec,MS_FILE_REC_START);

3.连接Filter

ms_filter_link(capture,0,tee,0);

ms_filter_link(tee,0, playback,0);

ms_filter_link(tee,1,rec,0);

4.开始调度

MSTicker *ticker=ms_ticker_new();

ms_ticker_attach(ticker, capture);

此后每隔10ms,就会对Filter处理一次。

5.停止调度,解除连接并资源回收

ms_filter_call_method_noarg(rec,MS_FILE_REC_CLOSE); //很重要,重写wav文件头

ms_ticker_detach(ticker, capture);

ms_ticker_destroy(ticker);

ms_filter_unlink(capture,0,tee,0);

ms_filter_unlink(tee,0, playback,0);

ms_filter_unlink(tee,1,rec,0);

ms_filter_destroy(capture);

ms_filter_destroy(playback);

ms_filter_destroy(tee);

ms_filter_destroy(rec);

到此,一个有本地录音回放的小程序就实现了。下面用一个视频回放并录制h.264裸码流的实例来说明mediastream2中对视频流是如何处理的。

本地录像机的实现

1.和本地录音机一样,还是先设计我们的Graph。

你可能感兴趣的:(流媒体)