1 FFmpeg的定义
FFmpeg既是一款音视频编解码工具,同时也是一组音视频编解码开发套件,作为编解码开发套件,它为开发者提供了丰富的音视频处理的调用接口。
FFmpeg提供了多种媒体格式的封装和解封装,包括多种音视频编码、多种协议的流媒体、多种色彩格式转换、多种采样率转换、多种码率转换等;FFmpeg框架提供了多种丰富的插件模块,包含封装与解封装的插件、编码与解码的插件等。
FFmpeg 中的“FF”指的是“Fast Forward”,曾经有人写信给FFmpeg 的项目负责人询问“FF”是不是代表“Fast Free”或者“Fast Fourier”的意思。FFmpeg 中的“mpeg则是人们通常理解的 Moving Picture Experts Group(动态图像专家组),FFmpeg 是一个很全面的图像处理套件。其实从2000年发展至今,FFmpeg中的“FF”已经可以用各种组合进行理解,因为FFmpeg的强大足以支撑这些意义。
2 FFmpeg的历史
FFmpeg由法国天才程序员Fabrice Bellard在2000年时开发出初版;后来发展到2004年,Fabrice Bellard找到了FFmpeg的接手人,这个人就是至今还在维护FFmpeg的 Michael Niedermayer。Michael Niedermayer对FFmpeg的贡献非常大,其将滤镜子系统 libavfilter 加人FFmpeg项目中,使得FFmpeg的多媒体处理更加多样、更加方便。在FFmpeg 发布了0.5版本之后,很长一段时间没有进行新版本的发布,直到后来FFmpeg采用Git作为版本控制服务器以后才开始继续进行代码更新、版本发布,当然也是时隔多年之后了。
3 FFmpeg的基本组成
FFmpeg 框架的基本组成包含 AVFormat、AVCodec、AVFilter、AVDevice、AVUtil 等组成。
(1)FFmpeg的封装模块AVFormat
AVFormat中实现了目前多媒体领域中的绝大多数媒体封装格式,包括封装和解封装,如MP4、FLV、KV、TS等文件封装格式,RTMP、RTSP、MMS、HLS等网络协议封装格式。FFmpeg是否支持某种媒体封装格式,取决于编译时是否包含了该格式的封装库。根据实际需求,可进行媒体封装格式的扩展,增加自己定制的封装格式,即在AVFormat中增加自己的封装处理模块。
(2)FFmpeg的编解码模块 AVCodec
AVCodec中实现了目前多媒体领域绝大多数常用的编解码格式,既支持编码,也支持解。AVCodec除了支持MPEG4、AAC、MIPEG等自带的媒体编解码格式之外,还支持第三方的编解码器,如H.264(AVC)编码,需要使用x264编码器;H.265(HEVC)编码,需要使用x265编码器;MP3(mp3lame)编码,需要使用libmp3lame编码器。如果希望增加自己的编码格式,或者硬件编解码,则需要在AVCodec中增加相应的编解码模块,关于AVCode的更多相关信息以及使用信息将会在后面的章节中进行详细的介绍。
(3)FFmpeg的滤镜模块AVFilter
AVFilter 库提供了一个通用的音频、视频、字幕等滤镜处理框架。在AVFilter中,滤镜框架可以有多个输人和多个输出。我们参考下面这个滤镜处理的例子,如图1-2所示。
图所示样例中的滤镜处理将输入的视频切割成了两部分流,一部分流抛给crop滤镜与 vflip 滤镜处理模块进行操作,另一部分保持原样,当crop 滤镜与 vflip 滤镜处理操作完成之后,将流合并到原有的overlay图层中,并显示在最上面一层,输出新的视频。对应的命令行如下:
ffmpeg -i input.mp4 -vf "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" output.mp4
笔者使用的是linux系统,后面不明说都是linux环境
原图
变化后的图片
下面详细说明一下规则,具体如下
相同的Filter线性链之间用逗号分隔
不同的Filter 线性链之间用分号分隔
在以上示例中,crop与vfip使用的是同一个滤镜处理的线性链,split滤镜和overlay滤镜使用的是另外一个线性链,一个线性链与另一个线性链汇合时是通过方括号“门”括起来的标签进行标示的。在这个例子中,两个流处理后是通过[main]与[flip]进行关联汇合的。
split 滤镜将分割后的视频流的第二部分打上标签[tmp],通过crop 滤镜对该部分流进行处理,然后进行纵坐标调换操作,打上标签[fip],然后将[main]标签与[flip]标签进行合并,[fip]标签的视频流从视频的左边最中间的位置开始显示,这样就出现了镜像效果。
(4)FFmpeg的视频图像转换计算模块swscale
swscale模块提供了高级别的图像转换API,例如它允许进行图像缩放和像素格式转换,常见于将图像从1080p转换成720p或者480p等的缩放,或者将图像数据从YUV420P 转换成 YUYV,或者 YUV 转 RGB 等图像格式转换。
(5)FFmpeg的音频转换计算模块swresample
swresample模块提供了高级别的音频重采样API。例如它允许操作音频采样、音频通道布局转换与布局调整。
4 FFmpeg的编解码工具ffmpeg
ffmpeg是FFmpeg源代码编译后生成的一个可执行程序,其可以作为命令行工具使用。本节将通过实际的示例分析,对fpeg编解码工具的使用方法进行详细的介绍。首先列举一个简单的例子:
ffmpeg -i input.mp4 output.avi
这是一条简单的ffmpeg命令,可以看到,ffmpeg通过-i参数将input.mp4作为输入源输入,然后进行转码与转封装操作,输出到output.avi中,这条命令主要做了如下工作。
1)获得输人源 input.mp4。
2)转码。
3)输出文件 output.avi。
看似简单的两步主要的工作,其实远远不止是从后缀名为MP4的文件输出成后缀名为AVI的文件,因为在ffmpeg中,MP4与AVI是两种文件封装格式,并不是后缀名就可以决定的,例如上面的命令行同样可以写成这样:
ffmpeg -i input.mp4 -f avi output.dat
这条fmpeg命令相对于前面的那条命令做了一些改变,加了一个“-f”进行约束,“-f”参数的工作非常重要,它制定了输出文件的容器格式,所以可以看到输出的文件为output.dat,文件后缀名为.dat,但是其主要工作依然与之前的指令相同。
分析以上两个输出信息中的Output #0部分,可以看到输出的都是AVI,只是输出的文件名不同,其他内容均相同。
ffmpeg的主要工作流程相对比较简单,具体如下。
1)解封装(Demuxing)。
2)解码(Decoding)。
3)编码(Encoding)。
4)封装(Muxing)
其中需要经过6个步骤,具体如下
1)读取输入源。
2)进行音视频的解封装。
3)解码每一帧音视频数据。
4)编码每一帧音视频数据。
5)进行音视频的重新封装。
6)输出到目标
从图示的工作流程可以看出,ffmpeg首先读取输入源;然后通过Demuxer将音视频包进行解封装,这个动作通过调用libavformat中的接口即可实现;接下来通过Decoder进行解码,将音视频通过 Decoder解包成为YVU或者PCM这样的数据,Decoder通过libavcodec中的接口即可实现;然后通过Encoder将对应的数据进行编码,编码可以通过libavcodec中的接口来实现;接下来将编码后的音视频数据包通过Muxer进行封装Muxer 封装通过libavformat中的接口即可实现,输出成为输出流。
5 FFmpeg的播放器ffplay
FFmpeg不但可以提供转码、转封装等功能,同时还提供了播放器相关功能,使用FFmpeg的 avformat与avcodec,可以播放各种媒体文件或者流。如果想要使用fplay,那么系统首先需要有SDL来进行ffplay的基础支撑。
ffplay是FFmpeg源代码编译后生成的另一个可执行程序,与fmpeg在FFmpeg项目中充当的角色基本相同,可以作为测试工具进行使用,ffolay提供了音视频显示和播放相关的图像信息、音频的波形信息等。
6 FFmpeg的多媒体分析器ffprobe
ffprobe也是FFmpeg源码编译后生成的一个可执行程序。ffprobe是一个非常强大的多媒体分析工具,可以从媒体文件或者媒体流中获得你想要了解的媒体信息,比如音频的参数、视频的参数、媒体容器的参数信息等。
例如它可以帮助分析某个媒体容器中的音频是什么编码格式、视频是什么编码格式同时还可以得到媒体文件中媒体的总时长、复合码率等信息。
使用fprobe 可以分析媒体文件中每个包的长度、包的类型、帧的信息等。后面章节将会对fprobe进行详细的介绍,下面列举一个简单的例子,以对fprobe有一个基本的概念:
ffprobe input.mp4 -show_streams
结果
ffprobe version 7.1.1 Copyright (c) 2007-2025 the FFmpeg developersbuilt with gcc 11 (Ubuntu 11.4.0-1ubuntu1~22.04)configuration: --prefix=/usr/local/ffmpeg --enable-shared --enable-gpl --enable-version3 --enable-sdl2 --enable-debug=3 --enable-libx264 --extra-cflags=-fno-stack-check --enable-ffprobe --enable-ffplay --enable-encoders --enable-x86asm --enable-libfdk-aac --enable-libass --enable-libfreetype --enable-libmp3lame --enable-libtheora --enable-libvorbis --enable-nonfree --enable-libharfbuzz --enable-libfontconfig --enable-libfribidilibavutil 59. 39.100 / 59. 39.100libavcodec 61. 19.101 / 61. 19.101libavformat 61. 7.100 / 61. 7.100libavdevice 61. 3.100 / 61. 3.100libavfilter 10. 4.100 / 10. 4.100libswscale 8. 3.100 / 8. 3.100libswresample 5. 3.100 / 5. 3.100libpostproc 58. 3.100 / 58. 3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':Metadata:major_brand : isomminor_version : 512compatible_brands: isomiso2mp41encoder : Lavf57.41.100Duration: 00:05:22.95, start: 0.000000, bitrate: 1159 kb/sStream #0:0[0x1](eng): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 640x480 [SAR 133:100 DAR 133:75], 1027 kb/s, 23.98 fps, 23.98 tbr, 11988 tbn (default)Metadata:handler_name : VideoHandlervendor_id : [0][0][0][0]Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default)Metadata:handler_name : SoundHandlervendor_id : [0][0][0][0]
[STREAM]
index=0
codec_name=mpeg4
codec_long_name=MPEG-4 part 2
profile=Simple Profile
codec_type=video
codec_tag_string=mp4v
codec_tag=0x7634706d
width=640
height=480
coded_width=640
coded_height=480
closed_captions=0
film_grain=0
has_b_frames=0
sample_aspect_ratio=133:100
display_aspect_ratio=133:75
pix_fmt=yuv420p
level=1
color_range=unknown
color_space=unknown
color_transfer=unknown
color_primaries=unknown
chroma_location=left
field_order=unknown
refs=1
quarter_sample=false
divx_packed=false
id=0x1
r_frame_rate=2997/125
avg_frame_rate=2997/125
time_base=1/11988
start_pts=0
start_time=0.000000
duration_ts=3871500
duration=322.947948
bit_rate=1027775
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=7743
nb_read_frames=N/A
nb_read_packets=N/A
extradata_size=49
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
DISPOSITION:non_diegetic=0
DISPOSITION:captions=0
DISPOSITION:descriptions=0
DISPOSITION:metadata=0
DISPOSITION:dependent=0
DISPOSITION:still_image=0
DISPOSITION:multilayer=0
TAG:language=eng
TAG:handler_name=VideoHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]
[STREAM]
index=1
codec_name=aac
codec_long_name=AAC (Advanced Audio Coding)
profile=LC
codec_type=audio
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=fltp
sample_rate=44100
channels=2
channel_layout=stereo
bits_per_sample=0
initial_padding=0
id=0x2
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/44100
start_pts=0
start_time=0.000000
duration_ts=14241830
duration=322.943991
bit_rate=127473
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=13910
nb_read_frames=N/A
nb_read_packets=N/A
extradata_size=5
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
DISPOSITION:non_diegetic=0
DISPOSITION:captions=0
DISPOSITION:descriptions=0
DISPOSITION:metadata=0
DISPOSITION:dependent=0
DISPOSITION:still_image=0
DISPOSITION:multilayer=0
TAG:language=eng
TAG:handler_name=SoundHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]
根据输出内容可以看到,使用fprobe能够查看MP4文件容器中的流的信息,其包含了一个视频流,由于该文件中只有视频流,流相关的信息是通过[STREAMJ[/STREAM的方式展现出来的,在[STREAM]与I/STREAM]之间的信息即为该MP4文件的视频流信息。当视频文件容器中包含音频流与视频流或者更多路流时,会通过[STREAM]与[/STREAM]进行多个流的分隔,分隔后采用index来进行流的索引信息的区分。
7 FFmpeg的编译
linux下参考这里:Ubuntu20.04 编译安装 FFmpeg 详细教程_ubuntu 20.04 bianyi ffmpeg csdn-CSDN博客
8 FFmpeg的编码支持与制定
FFmpeg本身支持一些音视频编码格式、文件封装格式与流媒体传输协议,但是支持的数量依然有限,FFmpeg所做的只是提供一套基础的框架,所有的编码格式、文件封装格式与流媒体协议均可以作为FFmpeg的一个模块挂载在FFmpeg框架中。这些模块以第三方的外部库的方式提供支持,可以通过FFmpeg源码的configure命令查看FFmpeg 所支持的音视频编码格式、文件封装格式与流媒体传输协议,对于FFmpeg不支持的格式,可以通过 configure --help查看所需要的第三方外部库,然后通过增加对应的编译参数选项进行支持。帮助信息内容输出如下:
未尝试
这些外部库可以通过confgure 进行定制,在编译好的FFmpeg可执行程序中也可以看到编译时定制的FFmpeg的外部库。例如需要自己配置FFmpeg 支持哪些格式,比如仅支持H.264视频与AAC音频编码可以调整配置项将其简化如下:
./configure --enable-libx264 --enable-libfdk-aac --enable-gpl --enable-nonfree
其他支持的库可根据需求安装。
可以通过这些选项关闭不需要用到的编码、封装与协议等模块,验证方法如下
./confiqure --disable-encoders --disable-decoders --disable-hwaccels --disable-
muxers --disable-demuxers -disable-parsers --disable-bsfs --disable-protocols
--disable-indevs --disable-devices --disable-filters
未尝试,可根据需求enable和disable
FFmpeg 的编码器支持
./configure --list-encoders
从上面的输出信息中可以看出,FFmpeg支持的编码器比较全面,比如AAC、AC3、H.264、H.265、MPEG4、MPEG2VIDEO、PCM、FLV1的编码器支持
FFmpeg 的解码器支持
FFmpeg 源代码本身包含了很多的解码支持,解码主要是在输入的时候进行解码,也
可以理解为将压缩过的编码进行解压缩,关于解码的支持,可以通过./configure --list-decoders 命令来进行查看:
./configure --list-decoders
从上面的输出信息中可以看到FFmpeg所支持的解码器模块 decoders 支持了MPEG4、H.264、H.265(HEVC)、MP3 等格式。
FFmpeg 的封装支持
FFmpeg的封装(Muxing)是指将压缩后的编码封装到一个容器格式中,如果要查看FFmpeg源代码中都可以支持哪些容器格式,可以通过命令./configure --list-muxers 来查看:
./configure --list-muxers
从封装(又称复用)格式所支持的信息中可以看到,FFmpeg支持生成裸流文件,如H.264、AAC、PCM,也支持一些常见的格式,如MP3、MP4、FLV、M3U8、WEBM 等。
FFmpeg 的解封装支持
FFmpeg的解封装(Demuxing)是指将读人的容器格式拆解开,将里面压缩的音频流视频流、字幕流、数据流等提取出来,如果要查看FFmpeg的源代码中都可以支持哪些输入的容器格式,可以通过命令./configure --list-demuxers来查看:
./configure --list-demuxers
从解封装(Demuxer,又称解复用)格式支持信息中可以看到,FFmpeg源代码中已经支持的 demuxer 非常多,包含图片(image)、MP3、FLV、MP4、MOV、AVI等。
FFmpeg 的通信协议支持
FFmpeg不仅仅支持本地的多媒体处理,而且还支持网络流媒体的处理,支持的网络流媒体协议相对来说也很全面,可以通过命令./configure --list-protocols 查看:
./configure --list-protocols
从协议的相关信息列表中可以看到,FFmpeg支持的流媒体协议比较多,包括MMS、HTTP、HTTPS、HLS(M3U8)、RTMP、RTP,甚至支持TCP、UDP,其也支持使用file协议的本地文件操作和使用concat协议支持的多个文件串流操作,后面的章节中会有详细的介绍。