Python+FFmpeg视频处理入门

摘要: 介绍FFmpeg、视音频编解码技术、ffmpeg常用命令等。FFmpeg是领先的多媒体框架,能够解码、编码、转码、多路复用、多路分解、流化、滤镜和播放人类和机器创造的几乎所有东西。

FFmpeg简介

FFmpeg开源框架

FFmpeg是领先的多媒体框架,是视频处理最常用的开源软件,能够解码、编码、转码、多路复用、多路分解、流化、滤镜和播放人类和机器创造的几乎所有东西。它功能强大,用途广泛,大量用于视频网站和商业软件(比如 Youtube 和 iTunes),也是许多音频和视频格式的标准编码/解码实现。
FFmpeg本身是一个庞大的项目,包含许多组件和库文件,最常用的是它的工具ffmpeg(用于视音频转码的命令行工具)、ffplay(用于播放的应用程序)、ffprobe(用于查看文件格式的应用程序)。
PS:有不少人不清楚“FFmpeg”应该怎么读。它读作“ef ef em peg”。
ffmpeg's logo

FFmpeg的应用案例

使用FFMPEG作为内核视频播放器:
Mplayer,ffplay,射手播放器,暴风影音,KMPlayer,QQ影音…
使用FFMPEG作为内核的Directshow Filter:
ffdshow,lav filters…
使用FFMPEG作为内核的转码工具:
ffmpeg,格式工厂…
事实上,FFMPEG的视音频编解码功能确实太强大了,几乎囊括了现存所有的视音频编码标准,因此只要做视音频开发,几乎离不开它。

ffmpeg、ffplay、ffprobe

主要介绍一下ffmpeg工程包含的三个exe的使用方法。
ffmpeg的官方网站是:http://ffmpeg.org/
编译好的windows可用版本的下载地址:http://ffmpeg.zeranoe.com/builds/
该网站中的FFMPEG分为3个版本:Static,Shared,Dev。前两个版本可以直接在命令行中使用,他们的区别在于:Static里面只有3个应用程序:ffmpeg.exe,ffplay.exe,ffprobe.exe,每个exe的体积都很大,相关的DLL已经被编译到exe里面去了。Shared里面除了3个应用程序:ffmpeg.exe,ffplay.exe,ffprobe.exe之外,还有一些DLL,比如说avcodec-54.dll之类的。Shared里面的exe体积很小,他们在运行的时候,到相应的Dll中调用功能。Dev版本是用于开发的,里面包含了库文件xxx.lib以及头文件xxx.h,这个版本不包含exe文件。

打开系统命令行界面,切换到ffmpeg所在的目录,就可以使用这3个应用程序了。ffmpeg是用于转码的应用程序,ffplay是用于播放的应用程序,ffprobe是用于查看文件格式的应用程序。

雷霄骅-视音频编解码技术简介

本章几乎全部转载自雷霄骅-视音频编解码技术零基础学习方法,作了一些删减,建议直接阅读原文。

雷霄骅,CSDN知名技术博主。荣获2014、2015年度CSDN博客之星,2015年于美国微软总部荣膺微软大中华区MVP称号。他的技术博客突破了450万 访问量,其中的视音频技术专栏,被称为是视音频技术从业人员“优秀的参考手册”。
雷霄骅的blog
http://blog.csdn.net/leixiaohua1020
雷霄骅的知乎
https://www.zhihu.com/people/leixiaohua1020

封装格式Format profile

因为下载的来源不同,这些视频文件有不同的格式,用不同的后缀表示:avi,rmvb,mp4,flv,mkv等等(当然也使用不同的图标)。在这里需要注意的是,这些格式代表的是封装格式。何为封装格式?就是把视频数据和音频数据打包成一个文件的规范。仅仅靠看文件的后缀,很难能看出具体使用了什么视音频编码标准。总的来说,不同的封装格式之间差距不大,各有优劣。

有些封装格式支持的视音频编码标准十分广泛,应该算比较优秀的封装格式,比如MKV;而有些封装格式支持的视音频编码标准很少,应该属于落后的封装格式,比如RMVB。

MediaInfo查看编码信息

MediaInfo用来分析视频和音频文件的编码和内容信息,是一款是开源软件 (免费使用、免费获得源代码)。它除了提供DLL之外,本身也提供GUI工具用于查看视频信息。

使用MediaInfo可以获得多媒体文件的哪些信息?
内容信息:标题,作者,专辑名,音轨号,日期,总时间……
视频:编码器,长宽比,帧频率,比特率……
音频:编码器,采样率,声道数,语言,比特率……
文本:语言和字幕
段落:段落数,列表

MediaInfo支持哪些文件格式?
视频:MKV, OGM, AVI, DivX, WMV, QuickTime, Real, MPEG-1, MPEG-2, MPEG-4, DVD (VOB)…
(编码器:DivX, XviD, MSMPEG4, ASP, H.264, AVC…)
音频:OGG, MP3, WAV, RA, AC3, DTS, AAC, M4A, AU, AIFF…
字幕:SRT, SSA, ASS, SAMI…

MediaInfo的主要功能特点:
支持众多视频和音频文件格式
多种查看方式:文本,表格,树形图,网页……
自定义查看方式
信息导出:文本,CSV,HTML……
三种发布版本:图形界面,命令行,DLL(动态链接库)
与Windows资源管理器整合:拖放,右键菜单
国际化:有多种界面语言供选择
(软件界面)轻松实现本地化 (需要志愿者翻译语言文件)

下载地址:http://sourceforge.net/projects/mediainfo/files/binary/mediainfo-gui/

视频播放器原理

视音频技术主要包含以下几点:封装技术,视频压缩编码技术以及音频压缩编码技术。如果考虑到网络传输的话,还包括流媒体协议技术。

视频播放器播放一个互联网上的视频文件,需要经过以下几个步骤:解协议,解封装,解码视音频,视音频同步。如果播放本地文件则不需要解协议,为以下几个步骤:解封装,解码视音频,视音频同步。他们的过程如图所示:
视频播放器原理

解协议的作用,就是将流媒体协议的数据,解析为标准的相应的封装格式数据。视音频在网络上传播的时候,常常采用各种流媒体协议,例如HTTP,RTMP,或是MMS等等。这些协议在传输视音频数据的同时,也会传输一些信令数据。这些信令数据包括对播放的控制(播放,暂停,停止),或者对网络状态的描述等。解协议的过程中会去除掉信令数据而只保留视音频数据。例如,采用RTMP协议传输的数据,经过解协议操作后,输出FLV格式的数据。

解封装的作用,就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。

解码的作用,就是将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3,AC-3等等,视频的压缩编码标准则包含H.264,MPEG2,VC-1等等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV420P,RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。

视音频同步的作用,就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。

流媒体协议

流媒体协议是服务器与客户端之间通信遵循的规定。当前网络上主要的流媒体协议如表所示。
流媒体协议

RTSP+RTP经常用于IPTV领域。因为其采用UDP传输视音频,支持组播,效率较高。但其缺点是网络不好的情况下可能会丢包,影响视频观看质量。因而围绕IPTV的视频质量的研究还是挺多的。

因为互联网网络环境的不稳定性,RTSP+RTP较少用于互联网视音频传输。互联网视频服务通常采用TCP作为其流媒体的传输层协议,因而像RTMP,MMS,HTTP这类的协议广泛用于互联网视音频服务之中。这类协议不会发生丢包,因而保证了视频的质量,但是传输的效率会相对低一些。

此外RTMFP是一种比较新的流媒体协议,特点是支持P2P。

封装格式

封装格式(容器)的主要作用是把视频码流和音频码流按照一定的格式存储在一个文件(容器)中。现如今流行的封装格式如下表所示:
封装格式
由表可见,除了AVI之外,其他封装格式都支持流媒体,即可以“边下边播”。有些格式更“万能”一些,支持的视音频编码标准多一些,比如MKV。而有些格式则支持的相对比较少,比如说RMVB。
下面的命令查看ffmpeg支持的容器。
$ ffmpeg -formats

视频编码

视频编码的主要作用是将视频像素数据(RGB,YUV等)压缩成为视频码流,从而降低视频的数据量。如果视频不经过压缩编码的话,体积通常是非常大的,一部电影可能就要上百G的空间。视频编码是视音频技术中最重要的技术之一。视频码流的数据量占了视音频总数据量的绝大部分。高效率的视频编码在同等的码率下,可以获得更高的视频质量。
视频编码
由表可见,有两种视频编码方案是最新推出的:VP9和HEVC。目前这两种方案都处于研发阶段,还没有到达实用的程度。当前使用最多的视频编码方案就是H.264。

H.264的编码器X264
H.264仅仅是一个主流编码标准,而不是一个具体的编码器,H.264只是给编码器的实现提供参照用的。
基于H.264标准的编码器还是很多的,其中使用最多的就是x264了,性能强悍(超过了很多商业编码器),而且开源。其基本教程网上极多,不再赘述。Google推出的VP8属于和H.264同一时代的标准。总体而言,VP8比H.264要稍微差一点。此外,我国还推出了自己的国产标准AVS,性能也不错,但目前比H.264还是要稍微逊色一点。不过感觉我国在视频编解码领域还算比较先进的。

下一代编码标准H.265(HEVC)
下一代的编解码标准就要数HEVC和VP9了。VP9是Google继VP8之后推出的新一代标准。VP9和HEVC相比,要稍微逊色一些。HEVC在未来拥有很多大的优势,可参考:HEVC将会取代H.264的原因

未来实际使用的HEVC开源编码器很有可能是x265,目前该项目还处于发展阶段,可参考:x265(HEVC编码器,基于x264)介绍

主流以及下一代编码标准之间的比较,可以参考文章:视频编码方案之间的比较(HEVC,H.264,MPEG2等)。此外,在码率一定的情况下,几种编码标准的比较,可以参考:限制码率的视频编码标准比较(包括MPEG-2,H.263, MPEG-4,以及 H.264)。结果大致是这样的:HEVC > VP9 > H.264> VP8 > MPEG4 > H.263 > MPEG2。

下面的命令可以查看 FFmpeg 支持的编码格式,视频编码和音频编码都在内。
$ ffmpeg -codecs

编码器

编码器(encoders)是实现某种编码格式的库文件。只有安装了某种格式的编码器,才能实现该格式视频/音频的编码和解码。
以下是一些 FFmpeg 内置的视频编码器:
libx264:最流行的开源H.264编码器X264
NVENC:基于 NVIDIA GPU 的H.264编码器
libx265:开源的 HEVC 编码器
libvpx:谷歌的 VP8 和 VP9 编码器
libaom:AV1 编码器

音频编码器如下:
libfdk-aac
aac

下面的命令可以查看 FFmpeg 已安装的编码器。
$ ffmpeg -encoders

音频编码

音频编码的主要作用是将音频采样数据(PCM等)压缩成为音频码流,从而降低音频的数据量。音频编码也是互联网视音频技术中一个重要的技术。但是一般情况下音频的数据量要远小于视频的数据量,因而即使使用稍微落后的音频编码标准,而导致音频数据量有所增加,也不会对视音频的总数据量产生太大的影响。高效率的音频编码在同等的码率下,可以获得更高的音质。
音频编码
由表可见,近年来并未推出全新的音频编码方案,可见音频编码技术已经基本可以满足人们的需要。音频编码技术近期绝大部分的改动都是在MP3的继任者——AAC的基础上完成的。
这些编码标准之间的比较可以参考文章:音频编码方案之间音质比较(AAC,MP3,WMA等)。结果大致是这样的:AAC+ > MP3PRO > AAC> RealAudio > WMA > MP3。
此外杜比数字的编码标准也比较流行,但是貌似比最新的AAC稍为逊色:AC-3技术综述
下面的命令可以查看 FFmpeg 支持的编码格式,视频编码和音频编码都在内。
$ ffmpeg -codecs

ffmpeg命令行工具

这一章几乎全部参考了阮一峰-FFmpeg命令行视频处理入门教程,略作删减。

ffmpeg简介

ffmpeg处理视频,比桌面视频处理软件更简洁高效;同时,可以在python中借助ffmpy3包装器调用ffmpeg,实现批量处理。

基本语法
FFmpeg 的命令行参数非常多,可以分成五个部分。
$ ffmpeg {1} {2} -i {3} {4} {5}
上面命令中,五个部分的参数依次如下。
全局参数
输入文件参数
输入文件
输出文件参数
输出文件

参数太多的时候,为了便于查看,ffmpeg 命令可以写成多行。
$ ffmpeg \
[全局参数] \
[输入文件参数] \
-i [输入文件] \
[输出文件参数] \
[输出文件]

下面是一个例子。
$ ffmpeg \
-y \ # 全局参数
-c:a libfdk_aac -c:v libx264 \ # 输入文件参数
-i input.mp4 \ # 输入文件
-c:v libvpx-vp9 -c:a libvorbis \ # 输出文件参数
output.webm # 输出文件
上面的命令将 mp4 文件转成 webm 文件,这两个都是容器格式。输入的 mp4 文件的音频编码格式是aac,视频编码格式是H.264;输出的webm文件的视频编码格式是 VP9,音频格式是 Vorbis。

如果不指明编码格式,FFmpeg 会自己判断输入文件的编码。因此,上面的命令可以简单写成下面的样子。
$ ffmpeg -i input.avi output.mp4

处理过程
ffmpeg处理过程
ffmpeg调用libavformat库(含分离器)读取输入文件,分离出各类编码的数据包(流),当有多个输入文件时,ffmpeg试图跟踪最低时间戳实现任意输入流同步。编码数据包(除非是指定为流式拷贝,相关内容请参考特性描述对流式拷贝的说明)通过解码器解码出非压缩的数据帧(raw视频/PCM格式音频…),这些数据帧可以被滤镜进一步处理(下面会讲到)。经过滤镜处理的数据被重新编码为新的数据包(流),然后经过混合器混合(例如按一定顺序和比例把音频数据包和视频数据包交叉组合),写入到输出文件。

安装步骤
ffmpeg的官方网站是:http://ffmpeg.org/
编译好的windows可用版本的下载地址:http://ffmpeg.zeranoe.com/builds/
该网站中的FFMPEG分为3个版本:Static,Shared,Dev,下载Static版本。前面已经作了介绍,这里不再赘述。
然后,配置环境变量:
ffmpeg配置环境变量
可以参考【win10】 ffmpeg的安装

下面介绍FFmpeg几种常见用法。

查看文件信息

查看视频文件的元信息,比如编码格式和比特率,可以只使用-i参数。
$ ffmpeg -i input.mp4
上面命令会输出很多冗余信息,加上-hide_banner参数,可以只显示元信息。
$ ffmpeg -i input.mp4 -hide_banner

转换编码格式

转换编码格式(transcoding)指的是, 将视频文件从一种编码转成另一种编码。比如转成 H.264 编码,一般使用编码器libx264,所以只需指定输出文件的视频编码器即可。
$ ffmpeg -i [input.file] -c:v libx264 output.mp4
下面是转成 H.265 编码的写法。
$ ffmpeg -i [input.file] -c:v libx265 output.mp4

转换容器格式

转换容器格式(transmuxing)指的是,将视频文件从一种容器(封装格式)转到另一种容器(封装格式)。下面是mp4转webm的写法。
$ ffmpeg -i input.mp4 -c copy output.webm
上面例子中,只是转一下容器,内部的编码格式不变,所以使用-c copy指定直接拷贝,不经过转码,这样比较快。

调整码率

调整码率(transrating)指的是,改变编码的比特率,一般用来将视频文件的体积变小。下面的例子指定码率最小为964K,最大为3856K,缓冲区大小为 2000K。
$ ffmpeg \
-i input.mp4 \
-minrate 964K -maxrate 3856K -bufsize 2000K \
output.mp4

改变分辨率

下面是改变视频分辨率(transsizing)的例子,从1080p转为480p 。
$ ffmpeg \
-i input.mp4 \
-vf scale=480:-1 \
output.mp4
-1表示等比例缩放

提取音频

有时,需要从视频里面提取音频(demuxing),可以像下面这样写。
$ ffmpeg \
-i input.mp4 \
-vn -c:a copy \
output.aac
上面例子中,-vn表示去掉视频,-c:a copy表示不改变音频编码,直接拷贝。

添加音轨

添加音轨(muxing)指的是,将外部音频加入视频,比如添加背景音乐或旁白。
$ ffmpeg \
-i input.aac -i input.mp4 \
output.mp4
上面例子中,有音频和视频两个输入文件,FFmpeg 会将它们合成为一个文件。

添加字幕

ffmpeg -i input.mp4 -vf subtitles=”sample.ass” out.mp4
上面例子中,字幕以内嵌字幕形式(硬字幕,类似于水印)烧进mp4文件。
ffmpeg -i input.mkv -i subtitles.srt -c copy output.mkv
上面例子中,字幕以软字幕形式(字幕流,可以选择是否显示)嵌入mkv文件。
软字幕就是所谓的字幕流,和视频流、音频流同等地位。值得说明的是,并非所有的容器都支持字幕流,先进的MKV是支持的,MP4目前我只知道支持苹果的MOV text。

mkv与mp4的转换

MKV(Matroska Video File)是一种多媒体封装格式,本身是一种容器,可以把各种视频,音频和字幕等内容封装到一个文件里面的格式,MKV是开放,免费没有限制的格式,开发者承诺大家可以自由使用这种格式,和经这种格式所开发的软件,不会在这个格式普遍的时候变成一个商业的项目(给作者一个赞!)。

MP4是MPEG-4的简写,是由MPEG(Moving Picture Experts Group)这个组织制定出来的一种多媒体封装格式。之前这个组织比较成功的标准有MPEG-1, MPEG-2, MPEG-3等。解释一个容易搞错的问题,我们平时听音乐常用的MP3(MPEG-1 Layer 3)格式并不是MPEG-3的标准,而是MPEG-1中的音频压缩标准。

mp4和mkv

MKV通常用来存储对画质要求高的视频;MP4通常用来存储需要在移动设备上播放的视频;MP4有更好的兼容性,但视频质量比MKV略差;MKV有着更好的质量,但是文件大小更大,且兼容性略差。
mkv转mp4,可以参考Python+FFmpeg视频处理实例1 批量裁剪视频

截图

下面的例子是从指定时间开始,连续对1秒钟的视频进行截图。
$ ffmpeg \
-y \
-i input.mp4 \
-ss 00:01:24 -t 00:00:01 \
output_%3d.jpg
如果只需要截一张图,可以指定只截取一帧。
$ ffmpeg \
-ss 01:23:45 \
-i input \
-vframes 1 -q:v 2 \
output.jpg
上面例子中,-vframes 1指定只截取一帧,-q:v 2表示输出的图片质量,一般是1到5之间(1 为质量最高)。

裁剪视频

裁剪(cutting)指的是,截取原始视频里面的一个片段,输出为一个新视频。可以指定开始时间(start)和持续时间(duration),也可以指定结束时间(end)。
$ ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
$ ffmpeg -ss [start] -i [input] -to [end] -c copy [output]
下面是实际的例子。
$ ffmpeg -ss 00:01:50 -i [input] -t 10.5 -c copy [output]
$ ffmpeg -ss 2.5 -i [input] -to 10 -c copy [output]
上面例子中,-c copy表示不改变音频和视频的编码格式,直接拷贝,这样会快很多。
如果精准裁剪视频,可以参考Python+FFmpeg视频处理实例1 批量裁剪视频

ffmpy3

ffmpy3简介

ffmpy3是一个用于FFmpeg的Python包装器,最初是从ffmpy项目派生出来的。它根据提供的参数及其各自的选项编译FFmpeg命令行,并使用Python的子进程执行它。
ffmpy3类似于FFmpeg使用的命令行方法。它可以读取任意数量的输入“文件”(常规文件、管道、网络流、抓取设备等),并写入任意数量的输出“文件”。有关FFmpeg命令行选项和参数如何工作的详细信息,请参阅FFmpeg文档。
ffmpy3支持FFmpeg的管道协议。这意味着可以将输入数据传递到stdin并从stdout获得输出数据。
目前,ffmpy3已经为ffmpeg和ffprobe命令提供了包装器,但是应该可以用它运行其他ffmpeg工具(例如ffserver)。

安装步骤
安装:
pip install ffmpy3
导入:
from ffmpy3 import FFmpeg

需要将ffmpeg.exe放进.py文件所在文件夹下,否则报错ffmpy.FFExecutableNotFoundError: Executable ‘ffmpeg’ not found。

FFmpeg类
ffmpy3.FFmpeg(executable=’ffmpeg’, global_options=None, inputs=None, outputs=None)
ffmpeg参数
executable表示ffmpeg.exe的位置;global_options表示全局参数;inputs表示输入文件;outputs表示输出文件。

下面介绍ffmpy3几种常见用法。

格式转换

最简单的用法例子是将媒体从一种格式转换为另一种格式(在本例中是从MP4转换为MPEG传输流),同时保留所有其他属性:
from ffmpy3 import FFmpeg
ff = FFmpeg(inputs={‘test.mp4’: None},
outputs={‘output.ts’: None})
print(ff.cmd)
ff.run()

转码

如果同时我们想用不同的解码器重新编码视频和音频,我们必须指定额外的输出选项:
下面的例子:将音频编码为mp2格式,将视频编码为mpeg2video模式
ff = FFmpeg(inputs={‘test.mp4’: None},
outputs={‘output.ts’: ‘-c:a mp2 -c:v mpeg2video’})
print(ff.cmd)
ff.run()
这里a就是指audio,v就是指video

多路分解

一个更复杂的使用示例是将MPEG传输流解复用为单独的基本(音频和视频)流,并将它们保存在保存编解码器的MP4容器中(注意这里如何使用列表作为选项):
实现的效果就是音频与视频分离,音频放入了audio.mp4文件,视频在video.mp4文件
from ffmpy3 import FFmpeg
ff = FFmpeg(inputs={‘input.ts’: None},
outputs={‘video.mp4’: [‘-map’, ‘0:0’, ‘-c:a’, ‘copy’, ‘-f’, ‘mp4’],
‘audio.mp4’: [‘-map’, ‘0:1’, ‘-c:a’, ‘copy’, ‘-f’, ‘mp4’]})
print(ff.cmd)
ff.run()

多路复用

将多路视频和音频重新编码回MPEG传输流,即音频与视频的合成:
from ffmpy3 import FFmpeg
ff = FFmpeg(inputs={‘video.mp4’: None, ‘audio.mp4’: None},
outputs={‘output.ts’: ‘-c:v h264 -c:a ac3’})
print(ff.cmd)
ff.run()

python直接调用ffmpeg

采用ffmpy3写了近50个命令,感觉ffmpy3支持的ffmpeg语法比较少,无法实现ffmpeg的复杂功能;想到ffmpeg是命令行工具,只要用python调用命令行,仅可执行ffmpeg命令,直接跳过ffmpy3。
实现语法如下:
import os
command=”ffmpeg -i {0}-clip.mkv -an -vn -scodec copy {0}-clip.ass”.format(k,k)
print(command)
os.system(command)
上面例子,表示提取字幕。

参考文献

推荐阅读

雷霄骅-视音频编解码技术零基础学习方法
阮一峰-FFmpeg命令行视频处理入门教程
【FFmpeg】FFmpeg常用命令汇总+文档汇总

其他参考文献

ffmpeg 翻译文档
FFmpeg官方网站
ffmpy3官方文档
MediaInfo使用简介
视频格式:MKV和MP4的区别
ffmpy3与ffmpeg的简单使用

GeRongcun wechat
欢迎扫描二维码关注公众号一起成长~
0%