工作需要,接触了FFMPEG的开发,中间遇到了很多的坑,记录一下。
FFmpeg的名称来自MPEG视频编码标准,前面的“FF”代表“Fast Forward”,FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。可以轻易地实现多种视频格式之间的相互转换。
一、视频概念
- 容器/文件(Conainer/File):即特定格式的多媒体文件,比如mp4、flv、mkv等。
- 媒体流(Stream):表示时间轴上的一段连续数据,如一段声音数据、一段视频数据或一段字幕数据,可以是压缩的,也可以是非压缩的,压缩的数据需要关联特定的编解码器。
- 数据帧/数据包(Frame/Packet):通常,一个媒体流是由大量的数据帧组成的,对于压缩数据,帧对应着编解码器的最小处理单元,分属于不同媒体流的数据帧交错存储于容器之中。一般情况下:Frame对应压缩前的数据,Packet对应压缩后的数据。
- 编解码器(Codec):以帧为单位实现压缩数据和原始数据之间的相互转换的
- 复用(mux):把不同的流按照某种容器的规则放入容器,这种行为叫做复用(mux)
- 解复用(mux):把不同的流从某种容器中解析出来,这种行为叫做解复用(demux)
- 码率和帧率是视频文件的最重要的基本特征,对于他们的特有设置会决定视频质量。如果我们知道码率和时长那么可以很容易计算出输出文件的大小。
- 帧率:帧率也叫帧频率,帧率是视频文件中每一秒的帧数,肉眼想看到连续移动图像至少需要15帧。
- 码率:比特率(也叫码率,数据率)是一个确定整体视频/音频质量的参数,秒为单位处理的位数,码率和视频质量成正比,在视频文件中中比特率用bps来表达。
二、常见用法
最常使用的是ffmpeg提供的CLI工具,其常见使用方法为:
ffmpeg [global options] {[infile options]['-i' 'infile'] ...} {[outfile options] 'outfile' ...}
参数选项由三部分组成:可选的一组全局参数、一组或多组输入文件参数、一组或多组输出文件参数,其中,每组输入文件参数以‘-i’为结束标记;每组输出文件参数以输出文件名为结束标记。
基本选项
能力集列表
- -formats:列出支持的文件格式。
- -codecs:列出支持的编解码器。
- -decoders:列出支持的解码器。
- -encoders:列出支持的编码器。
- -protocols:列出支持的协议。
- -bsfs:列出支持的比特流过滤器。
- -filters:列出支持的滤镜。
- -pix_fmts:列出支持的图像采样格式。
- -sample_fmts:列出支持的声音采样格式。
常用输入选项
- -i filename:指定输入文件名。
- -f fmt:强制设定文件格式,需使用能力集列表中的名称(缺省是根据扩展名选择的)。
- -ss hh:mm:ss[.xxx]:设定输入文件的起始时间点,启动后将跳转到此时间点然后开始读取数据。
对于输入,以下选项通常是自动识别的,但也可以强制设定。
- -c codec:指定解码器,需使用能力集列表中的名称。
- -acodec codec:指定声音的解码器,需使用能力集列表中的名称。
- -vcodec codec:指定视频的解码器,需使用能力集列表中的名称。
- -b:v bitrate:设定视频流的比特率,整数,单位bps。
- -r fps:设定视频流的帧率,整数,单位fps。
- -s WxH : 设定视频的画面大小。也可以通过挂载画面缩放滤镜实现。
- -pix_fmt format:设定视频流的图像格式(如RGB还是YUV)。
- -ar sample rate:设定音频流的采样率,整数,单位Hz。
- -ab bitrate:设定音频流的比特率,整数,单位bps。
- -ac channels:设置音频流的声道数目。
常用输出选项
- -f fmt:强制设定文件格式,需使用能力集列表中的名称(缺省是根据扩展名选择的)。
- -c codec:指定编码器,需使用能力集列表中的名称(编码器设定为”copy“表示不进行编解码)。
- -acodec codec:指定声音的编码器,需使用能力集列表中的名称(编码器设定为”copy“表示不进行编解码)。
- -vcodec codec:指定视频的编码器,需使用能力集列表中的名称(编解码器设定为”copy“表示不进行编解码)。
- -r fps:设定视频编码器的帧率,整数,单位fps。
- -pix_fmt format:设置视频编码器使用的图像格式(如RGB还是YUV)。
- -ar sample rate:设定音频编码器的采样率,整数,单位Hz。
- -b bitrate:设定音视频编码器输出的比特率,整数,单位bps。
- -ab bitrate:设定音频编码器输出的比特率,整数,单位bps。
- -ac channels:设置音频编码器的声道数目。
- -an 忽略任何音频流。
- -vn 忽略任何视频流。
- -t hh:mm:ss[.xxx]:设定输出文件的时间长度。
- -to hh:mm:ss[.xxx]:如果没有设定输出文件的时间长度的画可以设定终止时间点。
流标识
FFMPEG的某些选项可以对一个特定的媒体流起作用,这种情况下需要在选项后面增加一个流标识。流标识允许以下几种格式:
- 流序号。譬如“:1”表示第二个流。
- 流类型。譬如“:a“表示音频流,流类型可以和流序号合并使用,譬如“:a:1”表示第二个音频流。
- 节目。节目和流序号可以合并使用。
- 流标识。流标识是一个内部标识号。
假如要设定第二个音频流为copy,则需要指定-codec:a:1 copy
音频选项
- -aframes:等价于frames:a,输出选项,用于指定输出的音频帧数目。
- -aq:等价于q:a,老版本为qscale:a,用于设定音频质量。
- -atag:等价于tag:a,用于设定音频流的标签。
- -af:等价于filter:a,用于设定一个声音的后处理过滤链,其参数为一个描述声音后处理链的字符串。
视频选项
- -vframes:等价于frames:v,输出选项,用于指定输出的视频帧数目。
- -aspect:设置宽高比,如4:3、16:9、1.3333、1.7777等。
- -bits_per_raw_sample:设置每个像素点的比特数。
- -vstats:产生video统计信息。
- -vf:等价于filter:v,用于设定一个图像的后处理过滤链,其参数为一个描述图像后处理链的字符串。
- -vtag:等价于tag:v,用于设定视频流的标签。
- -force_fps:强制设定视频帧率。
- -force_key_frames:显式控制关键帧的插入,参数为字符串,可以是一个时间戳,也可以是一个“expr:”前缀的表达式。如“-force_key_frames 0:05:00”、“-force_key_frames expr:gte(t,n_forced*5)”
滤镜选项
高级选项
- -re:要求按照既定速率处理输入数据,这个速率即是输入文件的帧率。
- -map:指定输出文件的流映射关系。例如 “-map 1:0 -map 1:1”要求将第二个输入文件的第一个流和第二个流写入到输出文件。如果没有-map选项,ffmpeg采用缺省的映射关系。
三、API使用
如果想集成ffmpeg到自己的项目中,可以编译ffmpeg的源码后引入到项目中使用
编译和裁剪
FFMpeg与大部分GNU软件的编译方式类似,是通过configure脚本来实现编译前定制的。这种途径允许用户在编译前对软件进行裁剪,同时通过对宿主系统和目标系统的自动检测来筛选参与编译的模块并为其设定合适的配置。但是,FFMpeg的configure脚本并非如通常的GNU软件一样通过配置工具自动生成,而是完全由人工编写的。configure脚本生成的config.mak和config.h分别在Makefile和源代码的层次上实现编译的控制。
通过运行“./configure –help”可以了解到脚本支持的参数,这些参数大体分为下面几类:
- 标准选项——GNU软件例行配置项目如安装路径等。例:–prefix=…,……
- 列出当前源代码支持的能力集,如编解码器,解复用器,输入输出设备,文件系统等。例:–list-decoders,–list-encoders,……
- 授权选项:–enable-version3,–enable-gpl,–enable-nofree。代码的缺省授权是LGPL v2,如果要使用以LGPL v3、GPL授权的模块或者某些不遵循自有软件授权协议的模块,必须在运行configure时显式使能相应的选项。
- 编译、链接选项。例:–disable-static,–enable-shared,…… 缺省配置是生成静态库而不生成动态库,如果希望禁止静态库、生成动态库都需要显式指定。
- 可执行程序控制选项,决定是否生成ffmpeg、ffplay、ffprobe和ffserver。
- 模块控制选项,筛选参与编译的模块,包括整个库的筛选,例如:–disable-avdevice;一组模块的筛选,例如:–disable-decoders,单个模块的筛选,如:–disable-decoder=… 等。
- 专家级选项,允许开发者进行深度定制,如交叉编译环境的配置、自定义编译器参数的设定、指令级优化、debug控制等。
对于–disable、–enable类的控制选项,如果以–disable为前缀,则缺省是enable的,反之亦然。
总之,无论从商业角度还是技术角度出发,使用configure脚本对FFMpeg进行裁剪是最安全的方式,只有针对于某些configure无法满足的定制要求,才需要考虑修改configure脚本——甚至修改configure生成的配置文件。
以下是一个配置实例,实现运行与Android系统中的ffmpeg库的编译:
./configure --prefix=. --cross-prefix=$NDK_TOOLCHAIN_PREFIX --enable-cross-compile --arch=arm --target-os=linux --cpu=cortex-a8 \ --disable-static --enable-shared --enable-pic --disable-ffmpeg --disable-ffplay --disable-ffserver --disable-ffprobe \ --extra-cflags="-I$NDK_PLATFORM/usr/include" \ --extra-ldflags="-nostdlib -Wl,-T,$NDK_PREBUILT/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x \ -L$NDK_PLATFORM/usr/lib \ $NDK_PREBUILT/lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o $NDK_PREBUILT/lib/gcc/arm-linux-androideabi/4.4.3/crtend.o \ -lc -lm -ldl"
缺省的编译会生成4个可执行文件和9个库:可执行文件包括用于转码的ffmpeg、用于获取媒体信息的ffprobe、用于播放媒体的ffplay和用于推送媒体流的ffserver;库包括avutil、avformat、avcodec、avfilter、avdevice、swresample、swscale、postproc及avresample,其中,核心库有5个,分别为基础库avutil、文件格式及协议库avformat、编解码库avcodec、输入输出设备库avdevice和过滤器avfilter。
注意事项
- 当提示某个模块不存在或者失败的时候,CompilationGuide/Ubuntu – FFmpeg,在这个页面上查找安装命令
- 使用时提示缺失环境,export LD_LIBRARY_PATH=/opt/ocr_external/ffmpeg_install/lib
- ubuntu 编译FFmgeg执行./configure 时会报此错误。nasm/yasm not found or too old. Use –disable-x86asm for a crippled build.需要安装yasm的汇编编译器sudo apt-get install yasm
至此,ffmpeg的准备工作就差不多完成了