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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章