转自http://www.learndiary.com/2011/04/ubuntu-linux-%E4%B8%8B-ffmpeg-%E5%8F%8A-mencoder-%E5%AE%89%E8%A3%85%E4%BD%BF%E7%94%A8%E5%B0%8F%E7%BB%93/ ,感谢作者无私的分享贡献,让刚入门我这样子的菜鸟才有了方向
近段时间在学习 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月左右)。
结论:
像这种非经济驱动的开源工具,也许不一定像一些闭源的商业工具自成体系的较为完整的功能,但可以通过脚本把各种各有所长的开源命令行工具结合在一起,从而完成任务。以上内容和观点仅供参考,欢迎交流。