最近在做一个手机app的后端,这个手机app有安卓和ios两个版本主要面向的是国外用户。app名字就不透露了,国内外加起来有几十万的下载量。这个手机app有一项功能是需要将app录制的声音加上几幅图片合成视频,然后上传到facebook网站上分享给好友观看。本来这个功能是不需要后端介入的,因为手机上可以自己生成视频并且搞定上传就可以了。但由于: 1 android手机需要引入第三方的开源库ffmpeg,导致手机app的安装包大小会增大好几M。 2. 在手机上保存生成视频的资源文件图片也会增加一定安装包的大小。 3. android手机的配置五花八门,在一些配置较低的机型上完成合成视频的工作非常吃力,效率很低。 基于这些考虑,就把这项工作移到后端来做。
说到多媒体的处理,我一般都用ffmpeg这个开源库。这个库有两个特点。第一是功能很多,第二是支持的多媒体格式很全。这里需要感谢ffmpeg的开源软件工作者的辛勤工作和无私奉献。创造了这么好的开源工具给我使用,为我的工作提供了便利。可以从下面的网址了解这个库:
ffmpeg开源库的网址: http://ffmpeg.org/
ffmpeg下载网址:http://ffmpeg.org/download.html#releases
ffmpeg文档网址:http://ffmpeg.org/ffmpeg.html
ffmpeg faq:http://ffmpeg.org/faq.html
初学者可以从这个faq开始学习,因为这个faq讲的东西非常具体又详细。它介绍了ffmpeg的一些基本术语和简单用法。比如对于多段视频的合并这个功能,faq里的讲解很仔细易懂。它讲解了视频合并分成几种形式: 一种是多段视频一段播放完之后再播放一段,这种叫concat。 第二种是将两个视频在同一个窗口里播放,类似画中画的效果。这种方式叫做overlay。 对于不同的方式都解释了如何实现。
下面开始解释我的工作。
首先,我的需求是要将一段音频和几张图片合成一段视频。这几张图片需要采用轮播的方式进行循环的播放。
因此工作的第一步,我要知道这段音频的播放时间有多长,然后我才能计算出图片需要循环播放多少次。
用ffmpeg可以计算音频的播放长度,方法很简单直接运行ffmpeg -i 文件名
$ ffmpeg -i robot.mp3 ffmpeg version 0.11.1.git Copyright (c) 2000-2012 the FFmpeg developers built on Aug 10 2012 19:49:22 with gcc 4.1.2 (GCC) 20070115 (prerelease) (SUSE Linux) configuration: --disable-yasm --enable-libmp3lame --enable-libfaac --enable-libx264 --enable-gpl --enable-nonfree --enable-shared libavutil 51. 66.101 / 51. 66.101 libavcodec 54. 49.100 / 54. 49.100 libavformat 54. 22.101 / 54. 22.101 libavdevice 54. 2.100 / 54. 2.100 libavfilter 3. 5.102 / 3. 5.102 libswscale 2. 1.101 / 2. 1.101 libswresample 0. 15.100 / 0. 15.100 libpostproc 52. 0.100 / 52. 0.100 [mp3 @ 0x80744f0] max_analyze_duration 5000000 reached at 5015510 Input #0, mp3, from 'robot.mp3': Metadata: major_brand : M4A minor_version : 0 compatible_brands: M4A mp42isom encoder : Lavf54.22.101 Duration: 00:00:11.78, start: 0.000000, bitrate: 128 kb/s Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16, 128 kb/s
输出的结果的Duration就是robot.mp3的播放长度,格式为 xx:xx:xx:xx, 单位是 “小时:分钟:秒:百分之一秒”。 通过加权想加即可得到播放的长度。上文中例子的音频长度为11.78s。
工作的第二步是需要计算出整段视频一共有多少帧。计算方法是:
总帧数 = duration * fps 。
duration是第一步得到的音频长度,fps是视频每秒的帧数。
工作第三步将所有的图片文件拷贝到一个临时目录里,并通过循环的复制图片制作出视频的每一帧图片。例如图片的素材是image0.jpg image1.jpg image2.jpg, 需要拷贝到一个临时文件夹,并临时生成
image0000.jpg image0001.jpg image0002.jpg image0003.jpg image0004.jpg image0005.jpg 等等。
工作第四步就是要合成视频了。可以通过ffmpeg对图片和音频文件进行合并。进行合并的方法为:
ffmpeg -threads2 -y -r 10 -i /tmpdir/image%04d.jpg -i audio.mp3 -absf aac_adtstoasc output.mp4
参数的解释含义:
-threads 2 以两个线程进行运行, 加快处理的速度。
-y 对输出文件进行覆盖
-r 10 fps设置为10帧/秒
-i /tmpdir/image%04d.jpg 输入图片文件,图片文件保存为 image0001.jpg image0002.jpg ....
-i audio.mp3 输入的音频文件
-absf aac_adtstoasc 将结果的音频格式转为faac格式时需要这个选项。将音频格式转为faac是因为在iphone上某些音频格式的视频无法播放,例如mp3. 但faac格式的音频的视频在iphone上可以播放。-absf 的意思是设置一个bitstream filter进行某些转换。可以用ffmpeg -bsfs 查看所有支持的bitstream filter。 bitstream filter和 aac_adtstoasc的具体含义我也说不上。但是如果不用这个选项又会导致转换失败。
可以从这个链接下载一个合成的视频的例子:https://dl.dropbox.com/u/35106490/rap.mp4