由于工作需要,临时被老大吩咐去研究一个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来自两个视频的混音。

  真是不折腾,不成长啊!

 

工作记录--使用FFmpeg将一个视频文件中音频合成到另一个视频中的更多相关文章

  1. 【转载】SQL语句将一个表的数据写入到另一个表中

    在日常的数据库运维过程中,有时候需要将Select查询出来的数据集写入到另一个数据表中,其中一种方式是通过存储过程循环写入数据,另一种简便的方式是直接使用Insert Into语句后面跟上Select ...

  2. Visual Studio下,打开资源视图rc文件,提示在另一个编辑器中打开

    在网上搜索关键字: rc文件   提示在另一个编辑器中打开 很多地方的回答都是说: rc文件以代码形式打开了,只要关掉后再打开就可以了. 但是,很多时候,当关闭掉RC的代码文件以后,发现VS的RC文件 ...

  3. SQL语句将一个表的数据写入到另一个表中

    在日常的数据库运维过程中,有时候需要将Select查询出来的数据集写入到另一个数据表中,其中一种方式是通过存储过程循环写入数据,另一种简便的方式是直接使用Insert Into语句后面跟上Select ...

  4. 移动端控制视频点击播放点击下一个视频时自动停止播放&监听滑动溢出屏幕高度时停止播放

    直接上代码js部分: <script type="text/javascript"> var go;//记录video播放器位置 var video=document. ...

  5. 操作无法完成,因为文件夹已在另一个程序中打开(the action can't be completed because the folder or a file in it is open in another program)

    解决方法: 启动任务管理器——性能——资源监视器——CPU选项卡——关联的句柄——搜索句柄 ——(输入)要删除的文件夹名——搜索到与文件夹名句柄相关联的进程 (由于此程序进程正在调用文件夹,才造成了对 ...

  6. win10无法删除文件夹(其中的文件或者文件夹已在另一个程序中打开)怎么办?

    1. 右键点击任务管理器 2.打开资源监视器 3.搜索任务,结束任务(可能会死机)

  7. mysql中如何使用一句话将一个表的数据导入到另一个表中:insert into ...select

    INSERT INTO cdcd2015(`filename`,`xmlfile`,`updatetime`,`isDel`) SELECT `filename`,`xmlfile`,`updatet ...

  8. 编写一个程序,把指定目录下的所有的带.java文件都拷贝到另一个目录中,拷贝成功后,把后缀名是.java的改成.txt。

    package example; import java.io.*; public class Test { public static void main(String[] args) throws ...

  9. sql语句将一个表的数据拷贝到另一个表中

    假定有一个a表,一个b表,要将a表的数据拷贝到b表中. 1.如果a表和b表结构相同. insert into b select * from a; 2.如果a表和b表的结构不相同. insert in ...

随机推荐

  1. vue-draggable-resizable 拖拽缩放插件

    安装: npm install --save vue-draggable-resizable 使用: <template>   <div style="height: 50 ...

  2. F. Cowmpany Cowmpensation dp+拉格朗日插值

    题意:一个数,每个节点取值是1-d,父亲比儿子节点值要大,求方案数 题解:\(dp[u][x]=\prod_{v}\sum_{i=1}^xdp[v][i]\),v是u的子节点,先预处理出前3000项, ...

  3. window 下mongodb 配置

    1.下载mongodb-win32-x86_64-2008plus-ssl-v3.6-latest 解压到 D:\mongodb 2.cmd => path是否有环境变量 如果没有请配置 3.创 ...

  4. LUOGU P1514 引水入城 (bfs)

    传送门 解题思路 拉了很长的战线,换了好几种写法终于过了..首先每个蓄水场一定是对沙漠造成连续一段的贡献,所以可以$bfs$出每种状态,然后做一次最小区间覆盖,但这样的复杂度有点高.就每次只搜那些比左 ...

  5. Consul 安装的与启动

    1.下载地址:https://www.consul.io/downloads.html linux 下载地址: wget https://releases.hashicorp.com/consul/0 ...

  6. mongdb 使用聚合函数异常

    异常信息: Command execution failed:  Error [The 'cursor' option is required, except for aggregate with t ...

  7. 条件渲染v-if

    <!DOCTYPE html> <html lang="zh"> <head> <title></title> < ...

  8. 《DSP using MATLAB》Problem 8.25

    用match-z方法,将模拟低通转换为数字低通 代码: %% --------------------------------------------------------------------- ...

  9. eclipse下项目复制改名注意事项

    当在Eclipse下复制Web工程时 1.需要修改复制后新工程源码文件下 .settings 文件夹下的org.eclipse.wst.common.component中的内容为本工程名,明细如图:

  10. 牛客NOIP暑期七天营-TG3 赛后题解

    目录 牛客NOIP暑期七天营-提高组3 A-破碎的矩阵 题目描述 link 题解 代码 B-点与面 题目描述 link 题解 代码 C-信息传递 题目描述 link 题解 牛客NOIP暑期七天营-提高 ...