近段時間在學習 Ffmpeg、Mencoder 音視頻轉換,大概在 Ubuntu 10.04、Ubuntu 10.10、Ubuntu Natty 測試版上安裝和使用過。重點是針對低分辨率的普通手機視頻,測試的手機爲 Bird V780,主要參數爲,視頻編碼:mpeg4、h263,音頻編碼:faac、amrnb,容器格式:mp4、3gp,分辨率:176×144;音樂文件格式:mp3
。下面對 Ubuntu Linux 下 Ffmpeg 及 Mencoder 安裝使用作個小結。
1、安裝:
安裝 Ubuntu 軟件倉庫裏的版本是很容易的,用 sudo apt-get install 命令就可以自動安裝上。但是官方倉庫裏面的版本比較陳舊,可能缺失一些功能和存在一些 bug 沒有解決,更重要的是,一些需要的編碼支持沒有被官方版本編譯進去,如用於普通手機視頻的 faac、amr 音頻編碼支持等。而且,兩個軟件官方網站均推薦使用其 svn 或 git 開發版本。所以,下面着重總結編譯安裝 ffmpeg 和 mencoder。
爲了避免可能的衝突,在開始之前,我卸載了倉庫版本的相關軟件:sudo apt-get remove ffmpeg mencoder mplayer
獲取 Ffmpeg 開發版本:git clone git://git.videolan.org/ffmpeg.git ffmpeg
獲取 Mplayer 開發版本(包含了 mencoder):svn checkout svn://svn.mplayerhq.hu/mplayer/trunk mplayer
實際上 ./configure 配置 Mplayer 時會自動從 Ffmpeg 的開發庫中下載 ffmpeg 最新開發版源碼供編譯 Mplayer 使用,因爲 Mplayer 和 Mencoder 會調用 Ffmpeg 的庫。而且,在當前的 Mplayer 編譯中,如果沒有特別設定,Mplayer 會把 Ffmpeg 的庫編譯成靜態庫編入 Mplayer 或 Mencoder 的二進制文件中,使這兩個文件達到約14M左右。但是,我爲了保險起見,編譯 Ffmpeg 時就使用單獨下載的源碼。
通過事先的瞭解或在二者源碼樹下面執行 ./configure –help 得到配置幫助,得到編譯額外編碼支持庫的信息,如:libfaac, libopencore_amrnb 等。你可以據此計劃需要安裝哪些額外編碼庫。
然後是根據你的需要安裝額外編碼庫。在 Ubuntu 下,可以用 apt-get 安裝那些庫:如:
sudo apt-get install libx264-dev libxvidcore-dev libopencore-amrwb-dev \ libopencore-amrnb-dev libfaad-dev libfaac-dev libmp3lame-dev \ libtwolame-dev liba52-0.7.4-dev libcddb2-dev libcdaudio-dev \ libcdio-cdda-dev libvorbis-dev libopenjpeg-dev |
但是,在 configure ffmpeg 時,會報告:libx264 version must be >= 0.99
顯然是 Ubuntu 中的 libx264 版本低了,那麼 git clone git://git.videolan.org/x264.git
得到 x264 的源碼再編譯安裝就行了。
當然,如果 Ubuntu 倉庫中的版本不能滿足你的需要,你可以選擇從源碼安裝。更多的從源碼安裝編解碼庫的信息可以參考 Mplayer 相關文檔。
另外,編譯 ffplay 需要 libsdl1.2-dev 庫:sudo apt-get install libsdl1.2-dev
下面進行 Ffmpeg 的編譯安裝。經過試驗,也許是由於 Ubuntu 中的一個 bug,當存在倉庫版本中的 libavutil、libavcodec、libavformat 等庫時,編譯安裝的 ffmpeg 執行失敗(比如報錯:ffmpeg: relocation error: /opt/ffmpeg20110404/lib/libavfilter.so.1: symbol av_expr_free, version LIBAVUTIL_50 not defined in file libavutil.so.50 with link time reference),普通的 apt-get remove 不行,要連配置文件一起去掉,用 apt-get purge才行 (我在 Ubuntu 10.10 中發現,apt-get remove 後,仍存在 /usr/lib/i686/cmov/ 目錄下面的相關文件)。如我使用了下面的命令徹底卸載了我認爲有關的一些庫:
sudo apt-get purge libavutil-dev libavutil50 libavutil-extra-50 \ libavcodec-dev libavcodec52 libavcodec-extra-52 libavformat-dev \ libavformat52 libavformat-extra-52 libavdevice-dev libavdevice52 \ libavdevice-extra-52 libavfilter-dev libavfilter1 libavfilter-extra-1 \ libswscale-dev libswscale0 libswscale-extra-0 libpostproc-dev \ libpostproc51 libpostproc-extra-51 gnome-desktop-environment |
最後那個 gnome-desktop-environment 如果不卸載掉,是無法同時卸載如:libavutil50 和 libavutil-extra-50 的,也無法清除掉 /usr/lib/i686/cmov 下面的內容,從而導致 ffmpeg 在 Ubuntu 中執行報錯。
我看卸載了 gnome-desktop-environment 只是會卸載如:totem、gnash、sound-juicer 等並不是核心的組件,不會影響平常的使用。如果確實需要保留這些東西,我覺得可以試試把原來 ffmpeg 和 mplayer 的倉庫版本文件強制刪除,但在軟件包管理系統中應該並沒有被卸載的記錄,再把 ffmpeg 和 mplayer 等安裝在 /usr 標準目錄下,用以替代原來的相應文件。不過,我沒有試過。
下面配置 ffmpeg :
./configure --enable-nonfree --enable-gpl --enable-version3 \ --enable-shared --enable-postproc --enable-libmp3lame \ --enable-libopenjpeg --enable-libvorbis --enable-libopencore-amrnb \ --enable-libopencore-amrwb --enable-libxvid --enable-libx264 \ --enable-libfaac --enable-pthreads --prefix=/opt/ffmpeg20110404 |
然後,按照常規的 make, sudo make install 就完成了,雙核電腦可以用 make -j 2 節省編譯時間。
因爲我將 ffmpeg 安裝在了非標準目錄,所以添加了庫文件搜索設置(使用 root 權限):echo "/opt/ffmpeg20110404/lib" > /etc/ld.so.conf.d/ffmpeg.conf && ldconfig -v
下面配置 mplayer (mencoder):
在編譯安裝 mplayer 之前,在 Ubuntu 下要安裝 libasound2-dev ,否則會因爲缺少 alsa 的聲音驅動而導致播放沒有聲音。
經過試驗,mplayer 的配置比較自動化,configure 程序會搜索相關編碼庫文件,如果存在則會自動啓用,而不用像 ffmpeg 那樣必須像“–enable-libmp3lame”那樣明確指定。不過,默認配置選項編譯的 mplayer 是靜態鏈接到它自帶的 ffmpeg 源碼中編譯的靜態鏈接庫,這導致了 mplayer 或 mencoder 的二進制文件達到了 14M 左右。這可以通過禁用 ffmpeg 靜態鏈接編譯(–disable-ffmpeg_a)和告知 ffmpeg 的頭文件和庫文件位置( –extra-cflags=”-I/opt/ffmpeg20110404/include” –extra-ldflags=”-L/opt/ffmpeg20110404/lib”)來達到動態鏈接到已經安裝完成的 ffmpeg 庫文件的目的。同樣,我把 mencoder 安裝在了非標準目錄,下面是我用的配置命令:
./configure --prefix=/opt/mplayer20110404 --disable-ffmpeg_a \ --extra-cflags="-I/opt/ffmpeg20110404/include" --extra-ldflags="-L/opt/ffmpeg20110404/lib" |
從 ./configure –help 中,與動態鏈接到 ffmpeg 庫可能相關的參數有:–enable-rpath –disable-ffmpeg_a –enable-dynamic-plugins,但我只用了 –disable-ffmpeg_a 就完成了動態鏈接到 已經安裝了的 ffmpeg 庫的目的,也沒有詳細研究其它的參數了。
安裝 ffmpeg 的 man 文檔需要:sudo make install-man
與 ffmpeg 類似,編譯安裝完成後使用 root 權限執行:echo "/opt/mplayer20110404/lib" > /etc/ld.so.conf.d/mplayer20110404.conf && ldconfig -v
另外,如果不需要 ffmpeg 和 mplayer 中的一些組件(如: ffplay, mplayer),可以在 configure 中設定。具體查看: ./configure –help
然後,把 ffmpeg 和 mencoder 的可執行文件路徑加入 PATH 環境變量,使用 root 權限執行:
echo "export PATH=\"/opt/ffmpeg20110404/bin:/opt/mplayer20110404/bin:\$PATH\"" >> /etc/profile |
2、使用
主要以轉換成普通手機(以 Bird V780 爲測試手機)可以播放的 176×144 分辨率的 3gp 或 mp4 文件爲例,小結一下 ffmpeg 和 mencoder 的使用。
總的來說,ffmpeg 轉換視頻比 mencoder 更傻瓜化,只要指定了必要的參數,它就能產生能在手機上播放的 3gp 文件,如下:
ffmpeg -i test10s.avi -ar 8000 -ac 1 -ab 10.2k -s 176x144 -aspect 11:9 \ -b 200k -r 15 outaspect.3gp #生成 h263+libopencore_amrnb 的 3gp 視頻 |
ffmpeg -i test10s.avi -b 200k -r 15 -s 176x144 -aspect 11:9 -acodec libfaac \ -ac 2 -ar 44100 -ab 128k outfaac.3gp #生成 h263+libfaac 的 3gp 視頻 |
但是用 Mencoder 轉換,我使用的可工作的命令行爲:
mencoder yyzs.rmvb -ss 160:0 -endpos 1:0 -of lavf -lavfopts format=mp4 -srate 44100 \ -vf-add crop=440:360,scale=176:144,harddup -ofps 15 -oac faac -faacopts \ br=128:mpeg=4:object=2:raw -ovc lavc -lavcopts vcodec=mpeg4:aglobal=1:vglobal=1 \ -o yyzs17tt10.mp4 |
在 Bird V780上測試,其中缺了:br=128:mpeg=4:object=2:raw aglobal=1:vglobal=1 都不能播放,缺了br=128:mpeg=4會變成6聲道從而不能播放。但在 Bird V780 手機上不能播放並不能說明在其它手機或電腦上不能播放。因爲可能是 mencoder 的 bug,到目前爲止,libopencore_amrnb 音頻編碼的 3gp 視頻不能正常轉換,後面會詳述。
Mencoder 的侷限及解決方案
上面說過,因爲可能是 mencoder 的 bug,到目前爲止,libopencore_amrnb 音頻編碼的 3gp 視頻不能正常轉換。因爲在我的測試中,轉換成的 3gp 視頻的音頻長度比實際長度短了五分之四,下面的例子是 10 秒的音頻被強制壓縮成了 2 秒:
/usr/local/bin/mencoder -noconfig all -oac lavc -ovc lavc -lavcopts \ vcodec=h263:vbitrate=200:acodec=libopencore_amrnb:abitrate=10200 \ -of lavf -ofps 15 -srate 8000 -vf scale=176:144 \ -af lavcresample=8000,channels=1,volnorm \ -o test10s.r33081.h263.openamrnb.3gp test10s.avi |
就算是把 mplayer 的版本換成原來的 1.0rc3,把 amr 的編碼器換成舊的 libamr_nb 也是同樣的效果。詳見:MENCODER: Sound problems trying to convert from anything to 3gp w/amrnb: http://bugzilla.mplayerhq.hu/show_bug.cgi?id=1603 。
解決方案暫時用 ffmpeg 來轉換需要編碼成 libopencore_amrnb 音頻編碼的視頻。上面有一個相應的 ffmpeg 使用示例。
另外,Mencoder 不能直接把視頻轉換成只包含音頻的音頻文件,只能是視頻轉換到視頻。解決方案有兩個:
1)、使用 ffmpeg 轉換,如下:
ffmpeg -i test.rmvb -vol 1000 test.mp3 |
上面那個 -vol 是爲增加音量加的,不加這個參數默認的音量好像是 256。這個參數比較有用,在 mencoder 轉換中好像控制音量只有一個 volnorm 聲音濾鏡參數(-af)用於在不失真的前提下最大化音量,而不能像 ffmpeg 這樣有量化的增加音量(但增加過大聲音可能會失真)。
2)、使用 mplayer 提取出 pcm 格式的音頻,再選擇其它工具轉換成純音頻文件,如下面是轉換成 mp3 的 shell 文件(其中使用了命名管道作爲格式轉換的中間傳遞,可以避免中間文件佔用磁盤空間及加快處理過程):
#!/bin/bash # usage: tomp3.sh yyzs.rmvb 02:00:00 00:10:00 yyzs2h.mp3 tempfile=`mktemp` rm $tempfile mkfifo $tempfile /usr/bin/mplayer -ss $2 -endpos $3 -vc null -vo null -ao \ pcm:fast:waveheader:file=$tempfile $1 & lame $tempfile $4 rm $tempfile |
後臺執行 mplayer 必須在腳本文件中執行,在終端中執行會出錯如下:
問題:爲什麼從命令行終端直接執行如:” /usr/bin/mplayer -vc null -vo null yyzs.rmvb & “會報錯:
mplayer: could not connect to socket mplayer: No such file or directory Failed to open LIRC support. You will not be able to use your remote control. ? |
也許你要問,既然 mencoder 轉換視頻音頻這麼多侷限,爲什麼不使用其它工具,如 ffmpeg 直接進行轉換呢?答案就是與 mplayer 被稱爲 Linux 世界的萬能播放器有關,通過支持閉源的 dll 等第三方解碼庫,mplayer 幾乎可以播放世面上的所有音頻視頻格式文件,包括那些封閉的特殊格式。mencoder 和 mplayer 同用一個解碼庫,理論上(還沒有碰到實踐中的意外)只要 mplayer 能夠播放,mencoder 就能進行解碼從而進行格式轉換。儘管網上有說法說 mencoder 的代碼很濫,但是它卻是 Linux 世界的其它轉換工具無法替代的,包括 ffmpeg。
Ffmpeg 的侷限
儘管 ffmpeg 轉換音頻、視頻比較方便,而且據說速度還非常快,但其中有一個非常顯著的侷限,而且這個侷限是設計理念造成的。就是 ffmpeg 不支持第三方封裝的編解碼器,致力於提供原生的編解碼器,詳見 ffmpeg 文檔的 FAQ:
http://www.ffmpeg.org/faq.html#SEC5 :
1.4 FFmpeg does not support codec XXX. Can you include a Windows DLL loader to support it? No. Windows DLLs are not portable, bloated and often slow. Moreover FFmpeg strives to support all codecs natively. A DLL loader is not conducive to that goal. |
比如下面的 2 個文件,用 ffmpeg 就不能正常轉換格式:
FullMetal[wmv+AAC]_remux-006.mkv ffplay播放、ffmpeg編碼圖像花
niceday.wmv 主要約有兩處ffplay播放、ffmpeg編碼圖像花
而用 mencoder 進行轉碼,用 mplayer 播放上面 2 個源文件效果無誤。但需要把額外的解碼器 wmvdomd.dll 放入 codecs 解碼器目錄,否則出現與 ffplay 播放相同的問題。
取長補短,綜合運用 mencoder 和 ffmpeg 進行音頻視頻轉換
使用命令行工具有一個好處就是可以用腳本把不同的命令行工具結合起來完成某一個任務。下面針對幾種情況小結一下。
1)、音頻轉換
從試驗的結果,單純的音頻轉換完全使用 ffmpeg 即可,因爲即使是視頻文件中的視頻部分有問題,音頻部分卻是可以被 ffmpeg 正常解碼從而轉換成純音頻文件(我的試驗中還沒有碰到不能轉換的)。
示例命令: ffmpeg -i niceday.wmv niceday.mp3
2)、轉換成 mencoder 支持的編碼格式(如:不需要轉換成 libopencore_amrnb 音頻編碼的視頻格式)
鑑於 mencoder 解碼格式的全面性,直接用 mencoder 轉換。
3)、轉換成 mencoder 不支持但是 ffmpeg 支持的編碼格式(如:libopencore_amrnb 音頻編碼的視頻格式)
可以直接用 ffmpeg 轉換;如果 ffmpeg 不能正常解碼,可以先用 mencoder 轉換成中間格式,再用 ffmpeg 由中間格式轉換成最終格式,示例如下:
#!/bin/bash # usage: convert3gp.sh yyzs.rmvb yyzs10.3gp 02:00:00 00:10:00 # usage: convert3gp.sh 原視頻 目的視頻 開始時間點 持續時間 echo "`date`: convert3gp.sh $1 $2 $3 $4 begin." >> timerec.log tempfile=`mktemp` rm $tempfile tempfile=$tempfile.mkv mkfifo $tempfile mencoder -ss $3 -endpos $4 -noconfig all -oac pcm -ovc lavc -lavcopts \ vcodec=h263:vbitrate=200 -of lavf -lavfopts format=mkv -ofps 15 \ -vf scale=176:144 -o $tempfile $1 & #經試驗,avi 的中間格式和未指定容器格式的默認情況,好像有時會出錯, #像這樣使用 mkv 中間格式的情況還沒出現過異常。 #mencoder -ss $3 -endpos $4 -noconfig all -oac pcm -ovc raw \ #-vf format=yuy2 -o $tempfile $1 & #中間格式可以使用 raw video,但是轉換時間要長一些。 #部分RV40 的視頻導出raw video 用默認的格式爲黑白顏色, #要把格式指定爲其它的格式如 -vf format=yuy2 才行 ffmpeg -y -i $tempfile -vcodec h263 -b 200k -r 15 -s 176x144 \ -aspect 11:9 -acodec libopencore_amrnb -ac 1 -ar 8000 -ab 10.2k -f 3gp $2 #雖然在中間格式中已經轉換成了 h263 的視頻部分,但如果不重新指定相關參數, #轉換成的視頻文件會出現“[h263 @ 0x14f81c0]warning: first frame is no #keyframe”的問題,從而導致在定位視頻時出現花屏的現象。 #ffmpeg -y -i $tempfile -vcodec h263 -b 200k -r 15 -s 176x144 \ #-aspect 11:9 -acodec libfaac -ac 2 -ar 44100 -ab 128k -f 3gp $2 rm $tempfile echo `date` >> timerec.log exit 0 |
轉換速度及質量問題
在相同的環境下作了一個測試,轉換一個 rmvb 文件6分鐘的視頻,目的視頻是可以在 Bird V780 上播放的 176×144 3gp 文件,視頻編碼採用 h263,音頻編碼採用 faac。腳本及測試記錄見附件:速度測試,下面是結果比較:
名稱 比特率 轉換時間 區別 ffmpegonly.3gp 336Kbps 3'22" 只用 ffmpeg 轉換,加 -async 1 參數; menonly.3gp 321Kbps 2'52" 只用 mencoder 轉換,harddup 視頻濾鏡,-oac faac 音頻編碼; menonly2.3gp 321Kbps 2'40" 只用 mencoder 轉換,harddup 視頻濾鏡,-oac lavc -ovc lavc -lavcopts acodec=libfaac 音頻編碼; intermkv.3gp 336Kbps 2'47" mencoder 和 ffmpeg 結合轉換,mencoder 無 harddup 視頻濾鏡,使用結果視頻參數,ffmpeg 指定視頻詳細參數 -vcodec h263 -b 200k -r 15 -s 176x144 -aspect 11:9; intermkv2.3gp 336Kbps 2'47" mencoder 和 ffmpeg 結合轉換,mencoder 加 harddup 視頻濾鏡,使用結果視頻參數,ffmpeg 指定視頻詳細參數 -vcodec h263 -b 200k -r 15 -s 176x144 -aspect 11:9; intermkv3.3gp 322Kbps 2'37" mencoder 和 ffmpeg 結合轉換,mencoder 加 harddup 視頻濾鏡,使用結果視頻參數,ffmpeg 未指定視頻詳細參數 -vcodec copy,缺失關鍵幀錯誤導致定位時花屏; interraw.3gp 336Kbps 3'56" mencoder 和 ffmpeg 結合轉換,mencoder 無 harddup 視頻濾鏡,使用 raw 視頻,ffmpeg 指定視頻詳細參數 -vcodec h263 -b 200k -r 15 -s 176x144 -aspect 11:9; interraw2.3gp 336Kbps 4'03" mencoder 和 ffmpeg 結合轉換,mencoder 加 harddup 視頻濾鏡,使用 raw 視頻,ffmpeg 指定視頻詳細參數 -vcodec h263 -b 200k -r 15 -s 176x144 -aspect 11:9 |
從測試結果可知:
1)、只用 mencoder 轉換時,採用 lavc 中 faac (libfaac) 的音頻編碼 menonly2.sh 比直接採用 faac 音頻編碼 menonly.sh 快 12 秒;
2)、採用 ffmpeg、mencoder 兩步轉換的 intermkv2.sh 比只採用 mencoder 的 menonly2.sh 慢 7 秒;
3)、只採用 ffmpeg 轉換 ffmpegonly.sh 比只採用 mencoder 的 menonly2.sh 慢 42 秒,比採用 ffmpeg、mencoder 兩步轉換的 intermkv2.sh 慢 35 秒;
4)、轉換中,mencoder 加與未加 harddup 視頻濾鏡轉換時間幾乎無差別;
5)、採用 ffmpeg、mencoder 兩步轉換時,採用 raw 視頻中間格式的 interraw2.sh 比採用結果視頻中間視頻格式的 intermkv2.sh 慢 76 秒;
6)、採用 ffmpeg、mencoder 兩步轉換時,當採用結果視頻中間視頻格式,ffmpeg 重新指定視頻編碼詳細參數的 intermkv2.sh 比直接使用 -vcodec copy 的 intermkv3.sh 慢 10 秒,但是直接使用 -vcodec copy 會出現缺失關鍵幀錯誤導致定位時花屏。
因爲轉換視頻是用於普通手機播放的低分辨率視頻,從轉換結果和比特率和直觀觀看來說看不出明顯的質量差別。
初步來看,如果遇到 ffmpeg 無法識別原始文件格式但能編碼成目的格式,而 mencoder 無法編碼成目的格式但能識別原始文件格式時,使用二者結合轉換手機低分辨率視頻是可行的。在我進行 rmvb 到 3gp 的轉換測試中,這種結合轉換比純粹使用 mencoder 約慢,但還比純粹使用 ffmpeg 轉換時快不少。估計是 ffmpeg 解碼 rmvb 文件時的效率沒有 mencoder 高的緣故吧。
其它問題
1)、在轉換寬銀幕電影到手機視頻的過程中,爲了使畫面的主要內容更加清晰,可以先截去兩邊超寬的部分再進行轉換,在 mencoder 中可以使用 crop 視頻濾鏡處理,例如原始爲 640×360 的 16:9 ,要轉換成 176×144 的 11:9,可以使用視頻濾鏡 -vf-add crop=440:360,scale=176:144 達到效果;
2)、在 ffmpeg 中,如果只截取中間一段轉換進行轉換,將 “-i 原始文件名“ 放在 “-ss 開始時間 -t 持續時間“ 的後面並且加上 “-async 1(避免音畫不同步)” 可以避免搜索不需要轉換的部分而浪費的大量時間。例如,在我的測試中,E7400 雙核電腦上,如果轉換一部2個半小時電影中2小時以後的10分鐘內容,真正轉換的時間只用大約1分鐘,而如果把 “-i 原始文件名“ 放在 “-ss 開始時間 -t 持續時間“ 的前面,則要增加大約10分鐘的定位搜索時間!詳見:question about “Buffering several frames is not supported. Please consume all available frames before adding a new one.”
3)、因爲多次的測試,上面的命令不一定是同一次的安裝,例如有時安裝在 /usr/local 下面,有時是安裝在 /opt/ 下面等;而且,版本也不一定是同一版本,但命令應該是至少可以在最近的版本中通用的(2011年4月左右)。