23.高级技术
连接音频或者视频文件
连接多媒体文件的方法有多种,下表列出了所有的连接方法:
concatenation:串联
使用命令行串联
prerequisites:先决条件
在 Windows 中,我们使用 copy 命令来连接多媒体文件,设置它的 flag 为 /B,表示使用二进制模式 ,在要连接的文件之间要加一个 + 符号。连接 N 个文件的通用 copy 命令形式如下:
copy /B file1+file2+...+fileN-1+fileN outputFile
例如,想要串联 videoclip1.mpg 和 videoclip2.mpg 并保存输出为 video.mpg ,命令如下:
copy /B videoclip1.mpg+videoclip2.mpg video.mpg
在类 Linux 和 OS X 系统上,我们可以使用 cat 命令完成串联,其命令形式为:cat file1 file2 > file3 。因此,我们可以修改之前的示例如下:
cat videoclip1.mpg videoclip2.mpg > video.mpg
使用 concat 协议进行串联
另一个选择是使用 concat 协议来完成串联操作,它的先觉条件和 copy 命令类似。例如,我们可以将之前的示例修改为使用协议来进行串联,命令如下:
ffmpeg -i concat:"videoclip1.mpg|videoclip2.
使用 concat filter 进行串联
有专门用于音频和视频串联的 filter :concat,其描述如下:
concat filter 可以良好工作的先觉条件:
-
所有的 段 的时间戳必须从 0 开始
-
所有 段 中的想对应的 流 其参数设置必须相同,尤其时视频的尺寸
-
推荐使用相同的帧率,否则输出可使用可变帧率
concat filter 可以用于多个格式文件的串联,示例如下:
ffmpeg -i input1.avi -i input2.avi -filter_complex concat output.avi
ffmpeg -i input1.avi -i input2.avi -filter_complex concat output.mp4
ffmpeg -i input1.avi -i input2.mp4 -filter_complex concat output.webm
ffmpeg -i input1.avi -i input2.mp4 -i input3.mkv -filter_complex concat=n=3 output.flv
ffmpeg -i input1.avi -i input2.avi -i input3.avi -i input4.avi -filter_complex concat=n=4 output.mp4
ffmpeg -i 1.avi -vf
其他类型的连接
- 音频合并(audio merging):将多个流合并为一个多通道的流,详情见《数字音频(Digital Audio)》一章。
- 将多个音频文件混合为一个文件,即将多个通道的音频混合为一个通道,详情见《数字音频(Digital Audio)》一章。
- 多路复用(multiplex):混合视频流和音频流为输出文件,详情见《FFmpeg基础(FFmpeg Fundamentals)》一章中的《媒体流的选择(Selection of media stream)》一节。
- 覆盖(overlay):见《覆盖(Overlay)》一章中的《图片中的图片(Picture in Picture)》一节。
移除 logo
一些视频中会包含特定的 logo,一般都位于左上角,例如录制的电视节目中就会包含该电视台的 logo。FFmpeg 中有 2 个特殊的过滤器可以用来移除 logo ,虽然最终的结果并不总是很完美,但总体来说可以接受。
delogo filter
例如,一张大小为 800 x 600 的图片在右上角有一个 logo,现在我们想要移除这个 logo ,下面的命令中,我们使用了 show=1 可选参数,因此在我们指定的 logo 矩形框会显示一个绿色边框,如果不设置这个参数,则不会有这个边框:
ffmpeg -i eagles.mpg -vf delogo=x=700:y=0:w=100:h=50:t=3:show=1 nologo.mpg
现在,我们更加精细的设置 logo 的位置,且不再显示其边框:
ffmpeg -i eagles.mpg -vf delogo=x=730:y=0:w=70:h=46:t=1 nologo.mpg
视频抖动部分的修复
在没有三脚架或者在车上进行拍摄视频时,视频中就可能会出现抖动,即:在水平或者垂直方向上出现的小范围的位移。在某些特定的情况下,我们可以使用 deshake filter 来修复这个问题:
我们可以按照 deshake 参数的默认顺序填入,也可以使用参数的名称直接为该参数赋值:
ffmpeg -i travel.avi -vf deshake fixed_travel.avi
ffmpeg -i travel.avi -vf deshake=contrast=160 fixed.avi
ffmpeg -i travel.avi -vf deshake=blocksize=4:filename
在视频中添加一个彩色边框
drawbox 过滤器可以在视频中精确绘制一个矩形边框,这在很多情况下会很有用,比如想要标识视频上的某个物体时。
现有一个 SVGA 大小的视频,我们想要在它上面绘制一个 600x400 大小的行色边框,位置在 x=150,y=0,命令如下:
ffmpeg -i ship.avi -vf drawbox=x=150:w=600:h=400:c=yellow ship1.avi
帧的数量检测
如果想要知道视频文件中一共包含多少帧,我们可以使用命令:
ffmpeg -i input.mpg -f null /dev/null
输出的最后两行如下所示:
frame= 250 fps=0.0 q=0.0 Lsize= 0kB time=00:00:10.00 bitrate= 0.0kbits/s
video:16kB audio:0kB subtitle:0 global headers:0kB muxing overhead -100.000000%
我们可以看到在 frame= 后有一个数字,它就是视频文件的全部帧数,我们也可以按照帧率和时长来计算全部的帧数,但这种方法只能计算一个大概值,并不精确。
对广告,过渡部分,编码损坏部分的检测
从电视,网络记录下来的长视频中可能会包含一些不属于视频或损坏的部分,如广告部分,过度部分,不完整的帧数据以及其他不想要的内容等。视频可能会包含全部填充为黑色的帧,我们可以使用 blackdect filter 来检测它,其描述如下:
例如,想要检测 mptestsrc 中的 黑色部分,命令如下:
ffmpeg -f lavfi -i mptestsrc -vf blackdetect -f sdl 'test'
使用 blackframe filter 检测
另一个检测黑色部分的过滤器是 blackframe,其描述如下:
blackdetect 和 blackframe 过滤器非常相似,但它们的输出非常不同。我们使用上述 blackdetech 使用的输入,然后用 blackframe 显示输出,如下图所示:
仅选择指定的帧作为输出
音频的 aselect filter 和 视频的 select filter,都可以精确指定有那些帧可以保留到输出,而那些不会输出。
由于 select 的默认表达式为 1 ,因此,下面两个 select filter 的用例效果相同:全部帧都会被选中为输出:
ffmpeg -i input.avi -vf select output.avi
ffmpeg -i input.avi -vf select=1 output.avi
选择 20 到 25 秒中间的帧,命令为:
ffmpeg -i input.avi -vf select="gte(t\,20)*lte(t\,25)" output.avi
想要仅选择帧内(intraframes:又译为 帧内帧)为输出,命令如下:
ffmpeg -i input.avi -vf select="eq(pict_type\,I)" output.avi
以改变长宽比的形式改变尺寸
在之前的章节中,我们描述了如何使用 scale filter 来调整视频帧的大小。而我们也可以使用 setdar 和 setsar filter来改变视频帧的大小,它们分别用于改变 显示长宽比 DAR 和 取样长宽比 SAR,这两个长宽比之间的关系如下(详情请查阅《索引(Glossary)》):
DAR = width/height * SAR
一下是一些示例:
ffplay -i input.avi -vf setdar=r=16/9
ffplay -i input.avi -vf setdar=16/9
ffplay -i input.avi -vf setsar=r=1.234
ffplay -i input.avi -vf setsar=1.234
截屏
记录当前的屏幕显示并保存为一个文件,比如想要创建一个新手指引视频时,我们可以使用 dshow 输入设备 与 安装的 UScreenCapture Direct Show source filter 配合使用来完成,下载地址为:
http://www.umediaserver.net/bin/UScreenCapture.zip
抓取全屏的内容,命令如下:
ffmpeg -f dshow -i video="UScreenCapture" -t 60 screen.mp4
如果我们想要抓取特定的屏幕区域,我们使用 regedit 工具去修改一些特定的注册按键,详情可查看下载的 UscreenCapture.zip 中的 README 文件。
视频帧的细节信息
想要显示视频帧的详细信息,我们可以使用 showinfo filter,其描述如下:
例如下面的命令,我们将它输出的前三行信息显示出来:
ffmpeg -report -f lavfi -i testsrc -vf showinfo -t 10 showinfo.mpg
音频频谱
想要显现一个音频的频谱,我们可以使用 showspectrum filter,描述如下:
例如,下图就是下面的命令创建的频谱图:
ffmpeg -i audio.mp3 -vf showspectrum audio_spectrum.mp4
音频波形可视化
可以使用 showwaves filter 来可视化音频波形,其描述如下:
例如,我们要将 music.mp3 的波形保存为 waves.mp4,命令如下:
ffmpeg -i music.mp3 -vf showwaves waves.mp4
语音合成
有了额外的 libflite 库的配合,我们可以使用 flite 音频源来合成人类的声音,flite 是由 Flite 衍生而来的,是一个小型的可嵌入式 TTS (Text to Speech)引擎。它是由美国卡内基梅隆大学的CMU演讲小组开发的。Flite 完全是用 C 语言编写的,并重新实现了Festival架构的核心部分,并实现了这两个系统设计的语音之间的兼容性。美国卡内基梅隆大学的CMU演讲小组开发的 Festival Speech Synthesis System 是一个语音合成相关的系统。关于 Flite 更多的细节信息可以查阅 http://www.speech.cs.cmu.edu/flite
由于 flite 库非常大,因此默认的二进制版本中没有添加这个库,Windows 下包含 flite 库的二进制版本可以从以下目录下载:http://ffmpeg.tv/flite.php。Linux 和 OS X 的用户可以自己编译生成需要的程序。显示可用声音列表的命令如下:
ffmpeg -f lavfi -i flite=list_voices=1
从 Message.txt 中获取文本,然后使用一个女性声音将它读出来,命令如下:
ffmpeg -f lavfi -i flite=textfile=Message.txt:v=slt
将“Happy New Year to all”这就话保存为 wish.wav ,命令如下:
ffmpeg -f lavfi -i flite=text="Happy New Year to all":v=ka116 wish.wav
如果想要将语音的速度降低一些,命令如下:
ffmpeg -f lavfi -i flite=textfile=text.txt -af stempo=0.5 speech.mp3
将输出一次保存为多个格式
尽管在第一章中我们已经很明确地说明了语法的格式,但在这里我们仍然要提醒一下:在一条命令中,我们可以将输出的结果保存为多个格式。例如,我们可以将 flite 引擎的输出保存为 MP3 , WAV 和 WMA 格式:
ffmpeg -f lavfi -i flite=textfile=speech.txt speech.mp3 speech.wav speech.wma
输出保存的格式中,可以同时使用音频格式和视频格式,当然这是在输出同时有音频流和视频流的前提下:
ffmpeg -i clip.avi clip.flv clip.mov clip.mp3 clip.mp4 clip.webm
将额外的输入添加到 filtergraph 中
我们可以使用 -i 选项来指定输入,但如果输入有多个,在 filtergraph 中我们仅能使用第一个输入,它的标识 Label 为 [in] ,而剩下的输入在 filtergraph 中无法使用。如果我们需要在 filtergraph 中使用额外的输入,那么可以使用 amoive 源来指定一个音频输入,moive 源来指定一个视频输入,其详细描述如下:
例如,想要在输入文件上添加 logo 图标,则:
ffmpeg -i video.mpg -vf movie=logo.png[a];[in][a]overlay video1.mp4
现在,我们将 sp(seek_point)设置为 5 ,那么 logo 将会在视频第 5 秒的时候出现:
ffmpeg -i video.mpg -vf movie=logo.png:sp=5[a];[in][a]overlay video1.mp4