由于工作需要,临时被老大吩咐去研究一个FFmpeg工具,通过linux命令行去将一个视频中的音频提取出来并合成到另一个视频中,最终的效果是要保证2个视频中的音频都在一个视频中播放。
但是本人对FFmpeg一无所知,故先去了解一下FFmpeg是什么,没办法,生命在于折腾!
FFmpeg介绍
以下内容摘自维基百科:https://zh.wikipedia.org/wiki/FFmpeg
FFmpeg 是一个自由软件,可以运行音频和视频多种格式的录影、转换、流功能[1],包含了libavcodec——这是一个用于多个项目中音频和视频的解码器库,以及libavformat——一个音频与视频格式转换库。
“FFmpeg”这个单词中的“FF”指的是“Fast Forward(快速前进)”[2]。有些新手写信给“FFmpeg”的项目负责人,询问FF是不是代表“Fast Free”或者“Fast Fourier”等意思,“FFmpeg”的项目负责人回信说:“Just for the record, the original meaning of "FF" in FFmpeg is "Fast Forward"...”
这个项目最初是由Fabrice Bellard发起的,而现在是由Michael Niedermayer在进行维护。许多FFmpeg的开发者同时也是MPlayer项目的成员,FFmpeg在MPlayer项目中是被设计为服务器版本进行开发。
FFmpeg可使用众多参数,参数内容会根据ffmpeg版本而有差异,使用前建议先参考参数及编解码器的叙述。此外,参数明细可用ffmpeg -h
显示;编解码器名称等明细可用ffmpeg -formats
显示。
下列为较常使用的参数:
主要参数:
-i
——设置输入文件名。-f
——设置输出格式。-y
——若输出文件已存在时则覆盖文件。-fs
——超过指定的文件大小时则结束转换。-t
——指定输出文件的持续时间,以秒为单位。-ss
——从指定时间开始转换,以秒为单位。-t
从-ss
时间开始转换(如-ss 00:00:01.00 -t 00:00:10.00
即从00:00:01.00开始到00:00:11.00)。-title
——设置标题。-timestamp
——设置时间戳。-vsync
——增减Frame使影音同步。-c
——指定输出文件的编码。-metadata
——更改输出文件的元数据。-help
——查看帮助信息
影像参数:
-b:v
——设置影像流量,默认为200Kbit/秒。(单位请引用下方注意事项)-r
——设置帧率值,默认为25。-s
——设置画面的宽与高。-aspect
——设置画面的比例。-vn
——不处理影像,于仅针对声音做处理时使用。-vcodec( -c:v )
——设置影像影像编解码器,未设置时则使用与输入文件相同之编解码器。
声音参数:
-b:a
——设置每Channel(最近的SVN版为所有Channel的总合)的流量。(单位请引用下方注意事项)-ar
——设置采样率。-ac
——设置声音的Channel数。-acodec ( -c:a )
——设置声音编解码器,未设置时与影像相同,使用与输入文件相同之编解码器。-an
——不处理声音,于仅针对影像做处理时使用。-vol
——设置音量大小,256为标准音量。(要设置成两倍音量时则输入512,依此类推。)
FFmpeg实践
由上面的介绍可以看出,FFmpeg其实就是linux工具,可以通过linux命令行对视频音频进行处理。由于公司的linux系统已经安装过了,这里便不对FFmpeg的安装进行说明了。
可是怎么使用呢?首先我们要知道FFmpeg是怎么对视频音频进行管理的,-i 命令可以指定输入文件,如果不指定输出文件可以用来查看文件的存储结构,如输入以下命令:
ffmpeg -i L002BMG19041110.flv -i L002BMG19041110.patient.flv
我们指定了2个输入文件,Input #0代表是第一个输入文件,flv是文件的格式, from后面是文件名,duration为文件的时长,start是开始时间,bitrate是码率,Stream #0:0 是指第一个输入文件的第一个流文件,Video(视频流)/Audio(音频流),h264(视频编码)/acc(音频编码),以及其他音视频相关的参数。
而从图中可以看出,我们指定的2个输入文件都拥有1个视频流和1个音频流,并且它们的编码类型是一致的。那么目的就比较明确的了,我需要把第二个视频中的音频提取出来放到第一个视频中,并且保留第一个视频的音视频,但是第二个视频时长稍微长了一点,需要截取到和第一个视频时长一致。
可是如何提取出音频文件呢?通过Google了解到可以通过【-map】 参数去指定文件中的流文件进行输出,这个维基百科上没有提到啊,看来还有很多命令需要去慢慢挖掘。于是我通过下面命令试了一下,成功的将音频提取出来了。-map 0:1 将第一个输入文件的第二个流文件输出到out.wav中,因为上面已经看到了音频流都是在第二个位置。
ffmpeg -i L002BMG19041110.patient.flv -map 0:1 out.wav
真不错,感觉挺方便的,看来已经成功一半了,暗自窃喜中。已经将第二个视频的音频提取出来了,接下来将提取出来的音频添加到第一个视频就完事了。这个可以通过 copy 命令来实现,因为两个文件音频编码都是一致的,无需重新编码,故使用 -c 不重新编码,没有质量损失,-shortest选项将导致输出持续时间与最短输入流的持续时间相匹配。
ffmpeg -i L002BMG19041110.flv -i out.wav -c copy -shortest output.flv
看似好像要成功了,好像太顺利了一点,不太对劲!于是通过flv.js的demo页面进行了测试(地址:http://bilibili.github.io/flv.js/demo/),果然没有成功,没有out.wav中的声音。于是我看了一下output.flv的内容
里面还是有2个流,一个视频流一个音频流,看来是没有将out.wav的音频拷进去。这可怎么办好呢?梦里寻他千百度,蓦然回首...咦,发现有一条命令就可以搞定的方法,赶紧试试。
ffmpeg -i L002BMG19041110.flv -i L002BMG19041110.patient.flv -c copy -map 0 -map 1:1 -y -shortest output.flv
按照老外的说法 -map 0 可以取一个视频中的所有流,然后 -map 1:1 取第二个视频中音频流,因为outout.flv文件已经存在了,加个 -y 把旧文件替换掉。
不对啊,这个提示好像是 -map 0 的问题。于是我换成了 -map 0:0 试了一下
ffmpeg -i L002BMG19041110.flv -i L002BMG19041110.patient.flv -c copy -map 0:0 -map 1:1 -y -shortest out.flv
没有出错,但是测试发现只是把第一个视频的Video和第二个视频的Audio合成到一起了,那么能不能再加个 -map 0:1 把第一个视频中的Audio也加进来呢?
结果提示flv最多只能有一个Audio,那我换成MP4格式的呢
好像可以,于是我把out.mp4下载下来播放后发现还是只有第一个视频的Video和第二个视频的Audio,然后我又看了下这个out.mp4文件的内容:
MP4文件的内容和flv的不太一样,flv内容主要是流文件,而MP4还多了媒体数据。而且我们发现这个mp4文件里其实已经有1个Video和2个Audio了,但是 Stream #0:1 Audio 后面有个 (default),应该是默认播放这个音频,好像MP4一次只能播放一个音频,不能同时播放2个,看来我们目标还不是添加一个音频,而是把2个音频合成为一个。应该是这样没错了,哈哈,我真棒!
通过一段摸索,我又发现一个选项好像符合我的要求,那就是 -filter_complex ,经过多番搜索和多次尝试后,了解了下 -filter_complex 的用法,然后开始正式动手了,就是以下命令。将a代表音频,v代表视频,下面的意思是将第一个视频的Audio和第二个视频的Audio这两个输入合并为一个,然后通过 -map 0:v 取第一个视频的Video, -map "[a]" 取合成后的Audio,copy后输出到output.flv,-shortest取最短的时长进行合并。
ffmpeg -i L002BMG19041110.flv -i L002BMG19041110.patient.flv -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map 0:v -map "[a]" -c:v copy -shortest output.flv
由于这里吗,没有加 -y ,故中间提示我output.flv已存在,是否替换掉,输入y按回车就好了,输入n则会停止操作。感觉已经成功了啊,测试了后发现两个视频的声音都有了,因为flv最多支持1个音频,应该是两个音频合成了一个音频没错了。由于我是戴耳机听的,听着声音还是有点不太对,原来虽然是两个声音都播放,但是一个耳机播放一个,真让人头大。
又经过不断的寻找,终于在FFmpeg的官网找到一种说法
大概意思是可以通过 -ac 1 选项来将不同的声道合成为立体声。于是在上面命令的基础上加了 -ac 1
ffmpeg -i L002BMG19041110.flv -i L002BMG19041110.patient.flv -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map 0:v -map "[a]" -ac 1 -c:v copy -shortest output.flv
经过测试后,完美解决。最终效果为,将两个视频中的2个Video和2Audio通过 ffmpeg -i L002BMG19041110.flv -i L002BMG19041110.patient.flv -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map 0:v -map "[a]" -ac 1 -c:v copy -shortest output.flv 命令合成为一个视频,该视频中有1个Video和1个Audio,其中Video来自第一个视频,Audio来自两个视频的混音。
真是不折腾,不成长啊!
所有评论(0)