基于Android平台的流媒体播放器的设计
from: 基于Android平臺(tái)的流媒體播放器的設(shè)計(jì)
1引 言
隨著移動(dòng)通信技術(shù)和多媒體技術(shù)的迅速發(fā)展,融合手機(jī)、網(wǎng)絡(luò)、多媒體技術(shù)為一體的視頻監(jiān)控技術(shù)也有了長(zhǎng)足的進(jìn)步,通過(guò)移動(dòng)通信網(wǎng)絡(luò)提供流媒體服務(wù)已經(jīng)成為可能。全球移動(dòng)用戶數(shù)非常龐大,因此移動(dòng)流媒體服務(wù)具有巨大的市場(chǎng)潛力,也正成為移動(dòng)業(yè)務(wù)的研究熱點(diǎn)之一。在這一背景下,針對(duì)移動(dòng)網(wǎng)絡(luò)和移動(dòng)終端的特點(diǎn),提出移動(dòng)流媒體客戶端的解決方案很有現(xiàn)實(shí)意義。
本論文結(jié)合FFmpeg開源代碼中解碼流程,提出了移動(dòng)終端流媒體播放器基于分層體系架構(gòu)的設(shè)計(jì)方案。該設(shè)計(jì)的特點(diǎn)是在底層屏蔽不同類型文件解碼時(shí)對(duì)媒體流處理的差異,并且提供了對(duì)外部攝像頭設(shè)備的控制功能,最終在Android平臺(tái)[1]上實(shí)現(xiàn)該播放器。
2播放器整體設(shè)計(jì)方案
播放器無(wú)論播放本地文件或是網(wǎng)絡(luò)流媒體文件,都需要有獲取媒體數(shù)據(jù),解碼音視頻媒體流,將解碼后媒體數(shù)據(jù)顯示給用戶三個(gè)處理階段,根據(jù)0文件播放的流程中這三個(gè)明顯的處理階段,本文提出基于層次的播放器結(jié)構(gòu)設(shè)計(jì)。
由于本地文件和網(wǎng)絡(luò)流媒體文件的數(shù)據(jù)獲取方式是不相同的,若要保持上層解碼的一致性,需要對(duì)兩類文件進(jìn)行預(yù)處理,形成相同格式的數(shù)據(jù)提供給上層解碼。根據(jù)以上特性,結(jié)合文件解碼流程本文中面向?qū)崟r(shí)監(jiān)控的播放器設(shè)計(jì)采用分層結(jié)構(gòu),每層獨(dú)立完成任務(wù),使系統(tǒng)的耦合度降低,利于各層獨(dú)立擴(kuò)展而不影響上下層的應(yīng)用。從下至上依次是數(shù)據(jù)提取層、數(shù)據(jù)預(yù)處理層、音視頻解碼層和用戶界面。該流媒體播放器分層結(jié)構(gòu)如圖1所示。
用戶界面層主要提供用戶和播放器之間的交互接口,如播放本地文件時(shí)可以實(shí)現(xiàn)暫停、快進(jìn)、快退等功能,在觀看流媒體文件時(shí)可以通過(guò)數(shù)字鍵、導(dǎo)航鍵或者播放器上方向按鈕控制攝像頭的焦距、方向等信息。
音視頻解碼層主要有解碼選擇組件、各種主流音視頻格式的解碼器和多路媒體流之間同步的功能。解碼選擇組件從本地文件或者流媒體文件頭中獲取到媒體的解碼格式信息,根據(jù)該格式信息選擇相應(yīng)的解碼器對(duì)壓縮后媒體流進(jìn)行解碼。該部分是由FFmpeg修剪優(yōu)化后作為播放器的解碼模塊的。多路媒體之間同步包括視頻流和音頻流的同步,在播放本地文件時(shí)可能還需要字幕的同步。
數(shù)據(jù)預(yù)處理層對(duì)本地文件按照其媒體格式解封裝,獲取文件的音視頻或字幕等信息并將其按幀放入相應(yīng)上層待解碼緩沖區(qū)。對(duì)流媒體文件將去除RTP的包頭信息,并將RTP中音視頻信息組幀,將完整的數(shù)據(jù)幀傳給上層待解碼緩沖區(qū)。而封裝控制信息組件按照PELCO-D/P協(xié)議規(guī)定的文本格式封裝用戶的控制輸入,并將控制信息傳遞給下層。
數(shù)據(jù)獲取層的功能包括本地文件、流媒體文件的獲取和攝像頭控制信息的發(fā)送,前者只需讀取本地文件即可,流媒體文件的獲取需要從流媒體服務(wù)器獲取媒體數(shù)據(jù)信息。流媒體文件獲取部分包括前期會(huì)話協(xié)商部分、數(shù)據(jù)發(fā)送部分和數(shù)據(jù)緩沖部分。其中媒體信息協(xié)商部分需要使用RTSP協(xié)議[2]協(xié)商媒體流常規(guī)信息,如媒體類型(視頻和音頻)、傳輸協(xié)議(RTP/UDP/IP…)和媒體格式(H263、mpeg…)和媒體傳輸端口等信息。
3 FFmpeg到Android平臺(tái)的移植
FFmpeg是一個(gè)集錄制、轉(zhuǎn)換、音/視頻編碼解碼功能為一體的完整的開源解決方案。但本文中播放器只需要FFmpeg中對(duì)文件解封裝及音視頻解碼部分的功能,若將FFmpeg整個(gè)解決方案全部移植到目標(biāo)平臺(tái)上會(huì)造成大量的代碼冗余。并且FFmpeg代碼的開發(fā)時(shí)基于Linux操作系統(tǒng)的,并沒有考慮到手機(jī)平臺(tái)的處理能力小,能源不足等限制,因此針對(duì)手機(jī)上特定功能需求將FFmpeg代碼進(jìn)行修剪及優(yōu)化是十分重要的。
3.1 FFmpeg修剪及優(yōu)化
從FFmpeg如此龐大并且代碼結(jié)構(gòu)復(fù)雜的源代碼中找出本文需要的代碼確實(shí)是一項(xiàng)非常艱難的工作。在Linux下編譯運(yùn)行FFmpeg代碼時(shí)需要經(jīng)過(guò)configure、make、makeinstall三步才能將FFmpeg正確的編譯到Linux系統(tǒng)當(dāng)中。其中configure階段會(huì)生成一個(gè)configure.h和make文件,從這兩個(gè)文件中可以查找出該次編譯都編譯了那些文件。
經(jīng)研究發(fā)現(xiàn)在configure源代碼的時(shí)候可以加入很多配置參數(shù),其中參數(shù)分為基本選項(xiàng)參數(shù)、高級(jí)選項(xiàng)參數(shù)還有專門提供的優(yōu)化參數(shù)。優(yōu)化參數(shù)主要負(fù)責(zé)配置在編譯時(shí)需編譯的內(nèi)容。對(duì)FFmpeg的修剪也恰是將本系統(tǒng)中不需要的文件去除,因此本文利用選擇適當(dāng)?shù)膬?yōu)化參數(shù)的方法找出播放器所需文件。對(duì)這些參數(shù)仔細(xì)研究后,得出編譯時(shí)設(shè)置的參數(shù)如下:
./configure--enable-version3 --disable-encoders --enable-encoder=h263--enable-encoder= amr_nb --disable-parsers --disable-bsfs--enable-muxer=tgp --disable-protocols --enable-protocol =file。
以上面所示的參數(shù)配置編譯源文件時(shí),系統(tǒng)只將h263、amr_nb的編碼方法和3gp的文件封裝格式及其所有的解碼格式、解封裝文件的源代碼部分編譯到了鏈接庫(kù)。
此時(shí)被編譯到鏈接庫(kù)的源代碼集合即為本文所需的源代碼有效集,通過(guò)查找configure.h和make文件中的后綴名為.o文件,后綴名為.o的文件是編譯.c代碼時(shí)生成的目標(biāo)文件,每一個(gè)被編譯的.c文件都會(huì)生成.o文件,所以通過(guò)查看所有的后綴名為.o的文件名,便可得知在該配置參數(shù)下被編譯源文件有哪些,因此可以得出本文所需編譯的源文件最小集合。
FFmpeg開源代碼雖然能夠跨平臺(tái)編譯運(yùn)行,但其代碼的設(shè)計(jì)都是針對(duì)于PC機(jī)而言的,PC機(jī)和手機(jī)從CPU處理能力、能源、內(nèi)存等各方面的資源都具有很多大差異,本文中針對(duì)手機(jī)的特點(diǎn)主要從以下幾個(gè)方面優(yōu)化代碼:
1. 去除冗余代碼、規(guī)范程序結(jié)構(gòu)、減少if-else 的判斷、調(diào)整局部和全局變量、使用寄存器變量代替局部變量,減少不必要的代碼冗余,去除FFmpeg 調(diào)試過(guò)程中的打印語(yǔ)句;
2. 用邏輯移位運(yùn)算代替乘除操作,因?yàn)槌顺\(yùn)算指令的執(zhí)行時(shí)間遠(yuǎn)遠(yuǎn)大于邏輯移位指令,尤其是除法指令,使用邏輯移位運(yùn)算可以減少指令的運(yùn)行時(shí)間;
3. 注意循環(huán)函數(shù)的調(diào)用,盡量減少多重循環(huán)的使用,編寫代碼時(shí)盡量減弱上次循環(huán)與下次循環(huán)的相關(guān)性,減少不必要的代碼計(jì)算量;
4. 設(shè)置合理的緩存。針對(duì)FFmpeg 移植的目標(biāo)平臺(tái)Android平臺(tái),設(shè)置適合此本臺(tái)的緩存大小;。
這里對(duì)具體代碼的修改就不一一重復(fù)了。
3.2 FFmpeg移植
Google發(fā)布的NDK的makefile文件即Android.mk文件語(yǔ)法和普通的makefile文件有很多不同之處,在跨平臺(tái)編譯FFmpeg源代碼時(shí)并不能使用原有的makefile文件。所以移植的先決條件就是將FFmpeg里的makefile文件全部替換為NDK中的Android.mk文件。
通過(guò)分析FFmpeg的模塊結(jié)構(gòu)得知avutil是基礎(chǔ)模塊,avcodec模塊的編譯基于已經(jīng)編譯好的avutil模塊,avformat基于前兩者,按照這種模塊結(jié)構(gòu)本文編譯移植的順序?yàn)閍vutil、avcoedec、avformat,編譯的步驟詳細(xì)說(shuō)明如下:
1. 關(guān)于config.h和config.mak
首先說(shuō)明一下FFmpeg自帶的makefile的框架,FFmpeg在經(jīng)過(guò)configure命令之后會(huì)產(chǎn)生一個(gè)config.h文件和一個(gè)config.mak文件,這兩個(gè)文件加起來(lái)共有600-700個(gè)宏定義,用來(lái)描述編譯后代碼的各個(gè)方面參數(shù)設(shè)置,其中有關(guān)于體系架構(gòu)、編譯器、鏈接庫(kù)、頭文件、版本、編解碼器等等相關(guān)的宏定義。在這一部分必須要修改關(guān)于平臺(tái)差異方面的定義,比如必須把體系架構(gòu)改成Android平臺(tái)的ARMv5TE,這時(shí)文件編譯的時(shí)候指令集就會(huì)選擇ARM的指令集而不是X86的指令集。這兩個(gè)文件很重要,以后很多文件都要include config.h這個(gè)文件,編譯器會(huì)根據(jù)這個(gè)文件而選擇性對(duì)代碼進(jìn)行編譯。
2. 編譯libavutil.a
在libavutil建立一個(gè)Android.mk的文件,libavutil里的makefile文件需要調(diào)用subdir.mak,這個(gè)其實(shí)就是真正的編譯,但是書寫在Android.mk下,這個(gè)make文件可以不要,但需要直接把對(duì)應(yīng)的源文件引入,標(biāo)準(zhǔn)的makefile是指定.o目標(biāo)文件,但在Android.mk中需要直接指定.c源文件,Android.mk文件如下所示:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES:=adler32.c \
…… \
include $(BUILD_STATIC_LIBRARY)
編譯時(shí)可能會(huì)出現(xiàn)很多錯(cuò)誤,但這些問題歸結(jié)起來(lái)大部分都是因?yàn)橛行╊^文件沒有引入而產(chǎn)生的問題,只要引入相應(yīng)的頭文件后就可以了。比如不識(shí)別某些文件的size_t關(guān)鍵字,在該文件include stdio.h后就不報(bào)錯(cuò)了,其他類似錯(cuò)誤就不一一例舉了。
其它模塊按照相同的方法書寫Android.mk文件,移植到Android平臺(tái)最為本文中播放器的解碼模塊。
4 各層模塊詳解
4.1數(shù)據(jù)獲取層
該層完成主要功能為與流媒體服務(wù)器協(xié)商媒體信息細(xì)節(jié),并根據(jù)協(xié)商結(jié)果從服務(wù)器端獲取流媒體數(shù)據(jù),將流媒體數(shù)據(jù)存入緩沖區(qū),按照本文中緩沖策略將數(shù)據(jù)包發(fā)送給數(shù)據(jù)預(yù)處理層,其結(jié)構(gòu)圖如圖2所示:
本文中該層一共啟動(dòng)五個(gè)線程,其中一個(gè)線程中啟動(dòng)TCP連接,用于RTSP會(huì)話協(xié)商,并且在RTP數(shù)據(jù)傳輸期間,該TCP連接必須一直保留。兩個(gè)線程分別為接收音頻和視頻RTP數(shù)據(jù)的線程,另外兩個(gè)線程分別為接收以及發(fā)送音頻和視頻的RTCP數(shù)據(jù)包。
4.2 數(shù)據(jù)預(yù)處理層
本層對(duì)本地文件的預(yù)處理完全依賴于FFmpeg提供的功能文件解封裝功能,而流媒體文件的預(yù)處理需將一個(gè)或多個(gè)RTP 數(shù)據(jù)包整合在一起,這部分技術(shù)已經(jīng)相對(duì)成熟,本文將不再?gòu)?fù)述。
本文中流媒體播放器區(qū)別于其他普通流媒體播放器的最大特點(diǎn)即為能對(duì)外部帶有云臺(tái)的攝像頭進(jìn)行控制,例如焦距、上、下、左、右等方面的設(shè)置。所以本文中使用PELCO-D協(xié)議作為云臺(tái)控制協(xié)議。
中第一字節(jié)為同步字也稱起始符號(hào),通常都是0xFF。該符號(hào)字節(jié)用來(lái)檢測(cè)所采用的收發(fā)方式正確與否。第二字節(jié)填寫為目標(biāo)設(shè)備的地址,在命令字1字節(jié)中為對(duì)攝像頭光圈及焦距的控制。在命令字2字節(jié)為焦距及變倍控制,其中Bit4, Bit3, Bit2,Bitl為上下左右控制位,最后一個(gè)Bit0位總是0。數(shù)據(jù)1字節(jié)中,水平方向速度(00-3F)。數(shù)據(jù)2字節(jié),垂直方向速度,其數(shù)值同數(shù)據(jù)字節(jié)1。校驗(yàn)碼字節(jié)為前六個(gè)字節(jié)之和。
本文設(shè)計(jì)的PELCO-D協(xié)議文本,最初默認(rèn)情況下位命令字1、命令字2全部為0,數(shù)據(jù)字1和數(shù)據(jù)字2值為20H。通過(guò)上層發(fā)送的按鍵消息修改相應(yīng)命令字1、命令字2的相應(yīng)位。
目前本文中流媒體播放器只提供以上六種控制功能,該模塊根據(jù)上層出發(fā)的按鍵信息設(shè)置相應(yīng)位為1,計(jì)算字節(jié)的值,形成七個(gè)字節(jié)文本發(fā)送至外部設(shè)備,當(dāng)接收到上層按鍵停止的消息后,統(tǒng)一發(fā)送 {0xff,0x01,0x00,0x00,0x00,0x00,0x01,}停止命令。
4.3 解碼及顯示層
解碼層主要應(yīng)用 FFmpeg移植到Android平臺(tái)的代碼作為播放器的解碼模塊,該部分代碼支持包括avi、3gp、MPEG-4等90多種解碼格式及文件格式,并且經(jīng)過(guò)修剪優(yōu)化后的FFmpeg代碼效率和效能都得到了很大的提高。
顯示層本文主要應(yīng)用開源的SDL函數(shù)庫(kù)實(shí)現(xiàn),SDL(Simple DirectMediaLayer)是一個(gè)跨平臺(tái)的,免費(fèi)的開源軟件。該軟件應(yīng)用C語(yǔ)言開發(fā),對(duì)外提供多種平臺(tái)上圖像、聲音和其它輸入設(shè)備的簡(jiǎn)單接口。經(jīng)常用于游戲和其他多媒體應(yīng)用的開發(fā),該開源軟件可以運(yùn)行于多種操作系統(tǒng)上,其中包括Linux、PSP、Windows、Mac OSX等。同時(shí)SDL還具有視頻,音頻,線程,定時(shí)器,事件等功能。
5 總結(jié)
本文介紹了基于Android平臺(tái)的流媒體播放器的分層設(shè)計(jì)結(jié)構(gòu)及其各層的詳細(xì)設(shè)計(jì),該播放器的解碼庫(kù)源自經(jīng)過(guò)剪切優(yōu)化的FFmpeg源代碼,并且本文中的播放器提供了對(duì)外部攝像頭的控制功能,是其應(yīng)用范圍更為廣泛。
本文雖然完成了帶有控制功能的流媒體播放器的原型功能實(shí)現(xiàn),但還有很多例如 QoS、代碼優(yōu)化的問題需要進(jìn)一步的研究。
總結(jié)
以上是生活随笔為你收集整理的基于Android平台的流媒体播放器的设计的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编解码技术学习网站汇总
- 下一篇: 使用google开源框架Exoplaye