程偉倫,唐恒飛
(201600 上海市 上海工程技術(shù)大學(xué))
隨著汽車(chē)工業(yè)穩(wěn)步發(fā)展,汽車(chē)電子行業(yè)朝著信息化、媒體化方向轉(zhuǎn)變?;ヂ?lián)網(wǎng)技術(shù)的崛起、智能終端設(shè)備的良好應(yīng)用,人們對(duì)于車(chē)載多媒體設(shè)備的需求急劇增加,高性能的智能終端設(shè)備逐漸進(jìn)入大眾視野。智能終端設(shè)備搭載流媒體技術(shù)可使音頻和視頻在網(wǎng)絡(luò)上快速傳播并且無(wú)需下載等待。在高性能嵌入式設(shè)備上搭載流媒體技術(shù),可以實(shí)現(xiàn)互聯(lián)網(wǎng)通訊技術(shù)在車(chē)載領(lǐng)域的完美應(yīng)用,研究和設(shè)計(jì)這樣一款集音視頻一體化車(chē)載媒體播放總成也因此具備了現(xiàn)實(shí)意義和科研價(jià)值。
在網(wǎng)絡(luò)流媒體的傳輸過(guò)程中,音頻流和視頻流常?;旌显谝黄疬M(jìn)行傳輸,這就要求在對(duì)流數(shù)據(jù)進(jìn)行解封裝之后再進(jìn)行解碼操作。本文主要基于開(kāi)源多媒體處理工具FFmpeg 來(lái)實(shí)現(xiàn)音視頻的編解碼工作。FFmpeg 最早由Fabrice Bellard 發(fā)起,其支持的常見(jiàn)封裝格式有.mp4,.mp3,.flv,.avi 等,支持的常見(jiàn)傳輸協(xié)議有RTSP,RTMP,HTTP,RTP 等。FFmpeg 現(xiàn)如今幾乎包含了大部分音視頻編碼標(biāo)準(zhǔn),是音視頻開(kāi)發(fā)工作者的重要工具。
用戶(hù)通過(guò)點(diǎn)擊已經(jīng)移植到嵌入式設(shè)備的Qt界面程序中的下拉按鈕,選擇想要觀看的電臺(tái)播放頻道,系統(tǒng)程序會(huì)自動(dòng)加載rtmp 或rtsp 等網(wǎng)絡(luò)流媒體地址進(jìn)行解析并向服務(wù)器發(fā)起請(qǐng)求,服務(wù)器接收到請(qǐng)求后將壓縮好的視頻文件下發(fā)給嵌入式客戶(hù)端。嵌入式客戶(hù)端接收到文件壓縮包后,音頻方面:由FFmpeg 完成一系列解封裝、解碼、音頻重采樣后,調(diào)用Qt 的QAudioOutput 類(lèi)播放音頻;視頻方面:FFmpeg 完成一系列解封裝、解碼后,利用Qt 自帶的OpenGl 完成對(duì)視頻數(shù)據(jù)的著色與渲染,再調(diào)用自定義的MyVideoCall 完成對(duì)視頻畫(huà)面的不間斷更新。在音視頻同步處理方法方面,分析了3 種方案,選定以音頻時(shí)間戳為基準(zhǔn),視頻向音頻靠攏的方案。圖1 為整個(gè)車(chē)載終端音視頻功能的系統(tǒng)結(jié)構(gòu)框圖。
圖1 車(chē)載嵌入式流媒體終端的系統(tǒng)結(jié)構(gòu)框圖Fig.1 Block diagram of audio and video function system of vehicle terminal
由于嵌入式設(shè)備一般都小巧便攜,所以,其內(nèi)存資源往往有限。為了保證編碼質(zhì)量,本文在Windows 操作系統(tǒng)環(huán)境中完成軟件的編譯和運(yùn)行,實(shí)現(xiàn)音視頻數(shù)據(jù)的讀取與轉(zhuǎn)換,然后將其移植到嵌入式設(shè)備中。圖2為媒體文件的解碼示意圖。FFmpeg 庫(kù)文件豐富,能夠完成解碼、編碼、轉(zhuǎn)碼、封裝、解封裝、濾波和播放等眾多功能。
根據(jù)圖2 的解碼流程圖,F(xiàn)Fmpeg 對(duì)流媒體文件的解碼過(guò)程可以通過(guò)以下幾步來(lái)詳細(xì)敘述:
圖2 媒體文件的解碼流程Fig.2 Decoding flow of media file
(1)初始化庫(kù)文件。首先通過(guò)函數(shù)av_register_all(),初始化libavformat 庫(kù)并注冊(cè)所有的編碼器、解碼器和協(xié)議。然后需要調(diào)用avformat_network_init()函數(shù),初始化網(wǎng)絡(luò)庫(kù)。注冊(cè)成功后,軟件就可以rtsp,rtmp,http 協(xié)議的流媒體視頻。
(2)文件讀取模塊。avformat_open_input 函數(shù)將探測(cè)傳入的流媒體地址或文件格式,并設(shè)置傳入?yún)?shù),打開(kāi)數(shù)據(jù)流。
(3)獲取視頻流信息。avformat_find_stream_info 主要起到了讀入數(shù)據(jù)包(packets)的作用,然后從中提取出流的信息。這個(gè)函數(shù)不斷地更新流信息,而流信息主要是存放在AVStream這個(gè)結(jié)構(gòu)體中。而av_dump_format 函數(shù)將音視頻數(shù)據(jù)格式通過(guò)輸出到指定的文件或者控制臺(tái),方便了解輸入的視音頻格式。
(4)查找解碼器。獲取流信息的過(guò)程中會(huì)找到解碼器的id。
(5)讀取數(shù)據(jù)幀。av_read_frame 函數(shù)用于讀取具體的音視頻幀數(shù)據(jù),在完成解碼操作之前,需調(diào)用av_read_frame()獲得視頻或音頻的壓縮數(shù)據(jù),對(duì)該函數(shù)的調(diào)用是多次的、頻繁的。
音頻數(shù)據(jù)解碼出來(lái)之后,它的格式一般是不能直接播放的。音頻重采樣就是將原始的音頻數(shù)據(jù)變換為新的樣本格式(sample format)、聲道格式(channel)、采樣頻率(sample rate)以適應(yīng)不同聲音播放的要求。首先,利用swr_alloc()函數(shù)創(chuàng)建一個(gè)名為SwrContext 的重采樣上下文結(jié)構(gòu)體,通過(guò)函數(shù)swr_alloc_set_opts()函數(shù)將所需要的參數(shù)填充進(jìn)SwrContext 結(jié)構(gòu)體中。詳細(xì)代碼段如下并予以說(shuō)明。
上述代碼段中,actx 即為實(shí)例化SwrContext結(jié)構(gòu)體,填充完必要的音頻參數(shù)后通過(guò)swr_init()初始化該結(jié)構(gòu)體。最后,利用swr_convert()函數(shù)完成每一幀的音頻重采樣工作。完成重采樣后,需釋放SwrContext 結(jié)構(gòu)體。完成音頻的解碼和重采樣步驟后,調(diào)用Qt 的QAudioOutput 類(lèi)播放音頻即可。
由于FFmpeg 解碼的格式默認(rèn)是yuv 數(shù)據(jù),所以解碼后要將其轉(zhuǎn)換為RGB 數(shù)據(jù),此過(guò)程稱(chēng)為轉(zhuǎn)碼。本文采用Qt 自帶的OpenGL 完成對(duì)yuv數(shù)據(jù)的轉(zhuǎn)碼與渲染。OpenGL 是可用于跨平臺(tái)的應(yīng)用程序API,其強(qiáng)大功能可繪制小到簡(jiǎn)單圖形大到三維場(chǎng)景等一系列圖形界面。OpenGL 完成渲染工作依賴(lài)2 個(gè)重要的著色器(shader)即頂點(diǎn)著色器與紋理著色器。OpenGL 通過(guò)一個(gè)名為QGLShaderProgram 的對(duì)象來(lái)與著色器交互。著色器通過(guò)這個(gè)對(duì)象連接到OpenGL 應(yīng)用程序中。
OpenGL 視頻顯示的具體流程可簡(jiǎn)述如下:使用initializeOpenGLFunctionst()函數(shù)初始化OpenGL 函數(shù)庫(kù);使用QGLShaderProgram 類(lèi)中的addShaderFromSourceCode 函數(shù)將創(chuàng)建的著色器添加進(jìn)著色器程序中;再調(diào)用linkt()使著色器與著色器程序鏈接在一起;傳入已經(jīng)定義好的頂點(diǎn)坐標(biāo)與紋理坐標(biāo)并使之生效;使用glGenTexturest()為yuv 數(shù)據(jù)開(kāi)辟紋理內(nèi)存;通過(guò)glBindTexturet()將開(kāi)辟的紋理內(nèi)存指向的內(nèi)容與GL_TEXTURE_2D 綁定,即綁定成二維紋理;利用紋理過(guò)濾函數(shù)glTexParameterit(),將紋理像素映射成圖像像素,此處有多種過(guò)濾算法可以選擇,使用較多的是線性插值算法和鄰近插值算法。
流媒體數(shù)據(jù)經(jīng)過(guò)解碼后便得到了各自獨(dú)立的數(shù)據(jù),所以,音頻流和視頻流是獨(dú)自播放的。如何將音視頻流完美地流暢地輸送到用戶(hù)的聽(tīng)覺(jué)感官與視覺(jué)感官,一直以來(lái)都是音視頻開(kāi)發(fā)問(wèn)題中的重點(diǎn)。諸如流媒體傳輸、可視對(duì)講、本地播放等眾多領(lǐng)域的廠商都對(duì)音視頻同步提出了嚴(yán)苛的要求。一旦解碼出的音頻流和視頻流播放同步有偏差,隨著時(shí)間的推移其異步性將越來(lái)越大。
常用的同步策略有:(1)視頻同步到音頻;(2)音頻同步到視頻;(3)設(shè)置參考時(shí)鐘,視頻和音頻以參考時(shí)鐘為標(biāo)準(zhǔn)。由于人耳對(duì)于聲音的辨別效果更為敏銳,所以,本文采用第一種同步策略將視頻同步到音頻上。音視頻同步流程如圖3 所示。
圖3 媒體文件的解碼流程Fig.3 Decoding flow of media file
具體軟件實(shí)現(xiàn)方法是將音頻時(shí)間戳設(shè)為同步時(shí)間的參考對(duì)象,如果當(dāng)前視頻播放快于同步時(shí)間,利用msleep()延遲刷新,反之則加快刷新速率。
軟件設(shè)計(jì)完成后在Win10 操作系統(tǒng)上測(cè)試,通過(guò)Visual Studio2017運(yùn)行,運(yùn)行畫(huà)面如圖4所示。流媒體地址以CCTV-7 軍事農(nóng)業(yè)rtmp 地址測(cè)試,測(cè)試地址為rtmp://58.200.131.2:1935/livetv/cctv7。經(jīng)過(guò)測(cè)試,視頻播放無(wú)花屏且?guī)瑪?shù)穩(wěn)定,無(wú)明顯的延遲或卡頓現(xiàn)象;音頻播放流暢,無(wú)音頻損壞現(xiàn)象;軟件啟動(dòng)CPU 占用率低,無(wú)內(nèi)存泄漏現(xiàn)象;視音頻同步效果良好,基本符合用戶(hù)使用要求。
本文的目的在于研究并實(shí)現(xiàn)一款適用于車(chē)載的流媒體音視頻播放終端,為適應(yīng)相對(duì)便攜的嵌入式設(shè)備而采用FFmpeg 音視頻編解碼庫(kù)完成對(duì)流媒體數(shù)據(jù)的解碼播放。代碼復(fù)用性高,運(yùn)行效果流暢,音頻播放完整,視頻渲染良好,對(duì)嵌入式系統(tǒng)的開(kāi)發(fā)與應(yīng)用、音視頻編解碼的處理都有較好的導(dǎo)向與使用價(jià)值。