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