天天看點

FFMPEG Qt視訊播放器之SDL的使用

前面介紹了使用FFMPEG+Qt解碼視訊并顯示。

現在我們就着手給它加上聲音播放。

播放聲音有很多種方式:

以windows系統為例,可以使用如下方法播放音頻:

1.直接調用系統API的wavein、waveout等函數

2.使用directsound播放

這些方法都隻能在windows上使用,且相當難用(至少我這麼覺得),這個對于新手來說要把它們用好并穩定運作比較難。

想想我們使用FFMPEG的經驗,理論上應該也有現成的庫用來播放音頻的,百度了下,基本上有下面幾個主流的音頻開源庫:

1:OpenAL:這個庫比較好,強大,跨平台,不過這個庫的資料相對比較少。LGPL;

2:PortAudio:這個庫也很不錯,接口簡單,友善擷取 裝置,播放音頻。沒有看到硬體混音接口,或許多開幾個播放接口就可以實作。GPL,但是可以不開源自己的程式,其官方網站是這麼寫的,除非是我了解錯了。可以登入其官方網站檢視版權。

3:SDL:很有名的跨平台庫,可惜音頻方面,目前不支援采集音頻裝置,不過SDL2.0中已經保留接口了,應該以後會實作,不知道要到那個版本了。

4:SDL_audioin:如果你留心,應該可以找到這個庫,應為SDL不支援硬體裝置音頻采集,這個可以擷取裝置聲音。雖然跨平台,可是不支援 蘋果系統、iso當然也不支援,具體

其中OpenAL、ProtAudio和SDL這三個庫 我都有用過,覺得還是SDL比較好用,是以我們使用SDL來播放音頻。

使用SDL的好處:

1.網上資料多,學習起來友善

2.跨平台,Windows、Linux、Android、IOS通吃,基本上這4個系統就夠我們用了。

意味着我們可以使用相同的代碼在這些系統上直接運作。

3.庫體積相對比較小

SDL有一個缺點就是不能夠采集音頻,但是像安卓、IOS這樣的系統,在采集音頻的時候還是推薦直接用他們的API采集,是以我們完全可以容忍SDL不能采集音頻這個缺點。

并且FFMPEG是支援采集音頻的,必要的時候我們也可以直接使用FFMPEG采集。

SDL本身是一個多媒體庫,其最強大的地方不是在音頻上,而是在圖形圖形上。

那麼,為何我們前面不使用SDL顯示視訊呢?

在使用SDL的過程中,我發現,将SDL嵌入我們的窗體之後,窗體上方的控件樣式會失效(比如QSS樣式),這就意味着,放在窗體上方的按鈕或者其他控件不能夠透明。而我們的播放器當然需要在播放界面上放一個帶透明度的控制欄啦。而且目前也找不到好的解決方法,無奈之下,隻好将圖像顯示改成直接用繪圖的方法繪制在控件上。當然了,直接繪制的方法在效率上也不會差。是以就這麼幹了。

是以我們隻是使用SDL用來播放音頻,也算是大材小用了,不過管他呢,好用才是硬道理! 省事才是王道!

本篇文章我們不急着在上次的例子上加入音頻,而是先講解下如何使用SDL。

現在我們就開始使用SDL吧:

下面的例子講解了如何使用FFMPEG+SDL播放一個音頻檔案。

一、首先下載下傳SDL

SDL官網位址:http://www.libsdl.org/

我們現在都是在Windows系統下使用,是以直接下載下傳編譯好的版本就行了。

基本上的庫Windows的版本都有提供已經編譯好的版本,SDL也是如此:

FFMPEG Qt視訊播放器之SDL的使用

我們用的是mingw的編譯器,是以選擇下載下傳mingw的版本。

同時我們我們前面配置的編譯器是32位的,是以要選擇32位的版本。

二、引用SDL

當然在這之前,你需要先建立一個Qt工程,怎麼建立就不說了,請參考前面的文章,懶得動手的話,請直接下載下傳本文末尾的提供的工程吧。

不過學習的時候偷懶不是一個好習慣,而開發的時候偷懶就是強烈推薦的,比如盡量選用現成的東西來實作我們的功能,而不是啥都自己動手,比如這裡我們選擇SDL來播放音頻。

這裡我們要實作的是使用FFMPEG+SDL來播放音頻檔案,

SDL下載下傳完成後,首先将LIB庫解壓出來。

一樣的方法,改名成SDL2,并隻留下include和lib 這2個檔案夾。

将SDL2拷貝到工程目錄下,在工程的pro檔案中加入:

INCLUDEPATH += $$PWD/ffmpeg/include 
               $$PWD/SDL2/include 
 
LIBS += $$PWD/ffmpeg/lib/avcodec.lib 
        $$PWD/ffmpeg/lib/avdevice.lib 
        $$PWD/ffmpeg/lib/avfilter.lib 
        $$PWD/ffmpeg/lib/avformat.lib 
        $$PWD/ffmpeg/lib/avutil.lib 
        $$PWD/ffmpeg/lib/postproc.lib 
        $$PWD/ffmpeg/lib/swresample.lib 
        $$PWD/ffmpeg/lib/swscale.lib 
        $$PWD/SDL2/lib/x86/SDL2.lib      

這裡是同時引用了FFMPEG和SDL的工程檔案。

三、編寫代碼

加入SDL的頭檔案之後,編譯的時候會提示main函數沒有定義

原因是 SDL_main.h中有如下一段話:

#if defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE)
#define main    SDL_main
#endif      

可以看出這裡已經定義了一個main了,是以我們寫的程式中的main便不能生效了,解決方法:

在我們自己寫的main函數的前面加上:

#undef main
int main(int argc, char* argv[])
{
    ...
}      

FFMPEG讀取音頻檔案和解碼音頻的代碼,不做介紹了,基本上和前面視訊的操作類似。

這裡需要注意的一點是:

SDL播放音頻是通過回調函數的方式播放,且這個回調函數是在新的線程中運作,此回調函數固定時間激發一次,這個時間和要播放的音頻頻率有關系。

是以我們用FFMPEG讀到一幀音頻後,不是急着解碼,而是将資料存入一個隊列,等SDL回調函數激發的時候,從這個隊列中取出資料,然後解碼 播放。

代碼這裡不做介紹了,直接上完整的工程吧。

完整工程下載下傳位址:

繼續閱讀