基于Qt的嵌入式媒體播放器系統(tǒng)的設(shè)計(jì)
2)獲取文件信息函數(shù) const QString fileInfo();
用于獲得文件的各種信息并將結(jié)果保存在一個(gè)常量字符串中,便于其他函數(shù)調(diào)用。這些信息包括:播放時(shí)間、音頻格式、音頻比特率、音頻通道、音頻頻率、視頻格式、視頻比特率、視頻高度、視頻寬度等。
3)讀取音頻采樣函數(shù)
bool audioReadSamples(short* output , int channels, long samples, long samplesRead, int);
調(diào)用解碼器對音頻采樣數(shù)據(jù)進(jìn)行讀取,是音頻數(shù)據(jù)處理的核心部分。output表示待輸出文件指針,channels表示通道數(shù),samples表示采樣數(shù),samplesRead表示待讀取采樣數(shù)
4)讀取視頻幀函數(shù)
bool videoReadScaledFrame(unsigned char** output_rows, int, int, int in_w, int in_h,int out_w,int out_h,ColorFormat fmt,int);
調(diào)用解碼器對視頻幀進(jìn)行讀取,是視頻數(shù)據(jù)處理的核心部分。參數(shù)output_rows表示輸出列地址的指針,in_w、in_h、out_w、out_h分別表示輸入和輸出幀數(shù)據(jù)的寬度和高度,fmt表示采用的色彩模式,返回值用來判斷執(zhí)行是否成功。
5)音視頻同步函數(shù)定義:int Sync(File*fp,int auIndex,struct timeval*vtime);
fp為打開的多媒體文件指針,vtime為當(dāng)前正在播放的視頻文件的幀頭中提取的時(shí)間, auIndex指出當(dāng)前的音頻幀計(jì)數(shù),即當(dāng)前播放到了第幾幀。通過這些參數(shù)就可以計(jì)算出希望跳到的幀數(shù)和當(dāng)前幀數(shù)的差值,然后根據(jù)這個(gè)差值將音頻流向前(滯后)或向后(超前)跳即可。同時(shí)Sync函數(shù)還會將此差值int反饋給音頻解碼器,讓音頻解碼器修正數(shù)據(jù)流的時(shí)間戳,如此循環(huán),從而達(dá)到較好的音視頻同步效果。此函數(shù)的總體思想是在播放視頻數(shù)據(jù)流的同時(shí)啟動另一線程,打開對應(yīng)的音頻數(shù)據(jù)流播放,然后在視頻線程中來同步音頻數(shù)據(jù)。
此外還有插件初始化和注冊函數(shù) void pluginInit()、文件初始化函數(shù) void fileInit()、查找函數(shù) bool seek(long pos)、清空視頻數(shù)據(jù)函數(shù)flushVideoPackets()和清空音頻數(shù)據(jù)函數(shù)flushAudioPackets()、獲取下一數(shù)據(jù)包函數(shù) MediaPacket*getAnotherPacket(int stream)等,不再做詳細(xì)介紹。
3.2解碼庫模塊
解碼庫模塊的主要作用是為插件接口模塊提供解碼器,考慮到播放器的可移植性和可擴(kuò)展性,本系統(tǒng)采用了ffmpeg解碼庫。FFmpeg解碼庫是Linux下的一個(gè)開源解碼器集合,它支持多種音頻和視頻編解碼標(biāo)準(zhǔn),還支持轉(zhuǎn)文件格式、制作avi等,功能十分強(qiáng)大??梢栽趙indows下使用的ffshow插件,linux下的mplayer播放器都是使用的ffmpeg解碼庫。
解碼庫又包含解碼器和分離器。解碼器就是對音視頻數(shù)據(jù)流進(jìn)行解碼的組件,分離器就是把文件流中的數(shù)據(jù)分離為音頻數(shù)據(jù)流和視頻數(shù)據(jù)流的組件,音頻數(shù)據(jù)和視頻數(shù)據(jù)是分開解碼的,所以二者缺一不可。
3 嵌入式媒體播放器系統(tǒng)實(shí)現(xiàn)
3.1 數(shù)據(jù)流程總體設(shè)計(jì)
圖2為系統(tǒng)數(shù)據(jù)流程:首先輸入模塊從數(shù)據(jù)源(多媒體文件)讀入數(shù)據(jù),此時(shí)它將讀入文件頭,做一些基本的處理,如讀出文件長度,獲取此文件的編碼類型、比特率,判斷能否播放等;然后插件接口模塊會調(diào)用分離器插件將多媒體數(shù)據(jù)切分為視頻數(shù)據(jù)流和音頻數(shù)據(jù)流;再經(jīng)過視頻FIFO和音頻FIFO,排序處理;最后送入視、音頻解碼器調(diào)用相應(yīng)的解碼器進(jìn)行解碼,對于音頻數(shù)據(jù)就會進(jìn)行重采樣,對于視頻數(shù)據(jù)就會讀取相應(yīng)的幀,逐幀解碼;之后經(jīng)過采樣的音頻數(shù)據(jù)和經(jīng)過渲染覆蓋的視頻數(shù)據(jù)先進(jìn)行音視頻同步,再分別通過視、音頻輸出模塊輸出。這其中,數(shù)據(jù)的讀入、分離、解碼、輸出都是通過Qt提供的類庫以多線程同時(shí)進(jìn)行的,在解碼得同時(shí)程序也在不斷將數(shù)據(jù)讀入緩沖區(qū)并排序等待處理,以提高效率。
輸入模塊的主要功能是將用戶指定的多媒體文件讀入。由于不同格式的多媒體文件需要調(diào)用不同的解碼器才能正常打開,因此考慮到程序的模塊化將實(shí)際的文件打開工作交給插件接口模塊調(diào)用相應(yīng)的解碼器進(jìn)行,輸入模塊只對文件進(jìn)行一些基本的處理并對文件內(nèi)容進(jìn)行緩存,然后為插件接口模塊輸送原始數(shù)據(jù)流。用戶首先通過圖形用戶界面選定待播放文件發(fā)出打開指令,這將會使輸入模塊接收到一個(gè)信號并通過用戶界面?zhèn)骰氐男畔@得待播放文件的文件路徑和文件名。接下來輸入模塊會檢查文件路徑是否合法、文件是否為空,之后會向插件接口模塊發(fā)出信號,通知插件接口模塊查找可用的解碼器,為文件解碼做好準(zhǔn)備。下一步就是進(jìn)行調(diào)用播放初始化函數(shù)init(),其具體過程下面會詳細(xì)介紹,最后就是將工作移交給插件接口模塊,讓它調(diào)用對應(yīng)文件格式的解碼器的open()函數(shù)。
輸出模塊的主要功能是將通過解碼器解碼之后的音頻、視頻數(shù)據(jù)送到輸出設(shè)備(如LCD顯示屏、揚(yáng)聲器)輸出。根據(jù)輸出內(nèi)容的不同可以將輸出模塊劃分為音頻輸出和視頻輸出兩個(gè)子部分。這兩個(gè)部分基本上是相互獨(dú)立輸出的,通過插件接口模塊的同步控制讓它們在輸出時(shí)保持同步。視頻輸出和音頻輸出稍有不同,它利用Qt/Embedded可以直接控制FrameBuffer的特性來輸出視頻數(shù)據(jù)。幀緩沖區(qū)是顯卡上的內(nèi)存,使用幀緩沖區(qū)可以提高繪圖的速度和整體性能,與幀緩沖區(qū)有關(guān)的設(shè)備是/dev/fb0(主設(shè)備號29,次設(shè)備號0)。
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)
評論