
前言
FFMPEG是特别强大的专门用于处理音视频的开源库。你既可以使用它的API对音视频进行处理,也可以使用它提供的工具,如 ffmpeg, ffplay, ffprobe,来编辑你的音视频文件。
本文将简要介绍一下 FFMPEG 库的基本目录结构及其功能,然后详细介绍一下我们在日常工作中,如何使用 ffmpeg 提供的工具来处理音视频文件。
在讲解 FFMPEG 命令之前,我们先要介绍一些音视频格式的基要概念。
我们按使用目的可以将 FFMPEG 命令分成以下几类:
除了 FFMPEG 的基本信息查询命令外,其它命令都按下图所示的流程处理音视频
先是解复用获取到编码的数据包,然后将编码的数据包传送给解码器(除非为数据流选择了流拷贝,请参阅进一步描述)。 解码器产生未压缩的帧(原始视频/ PCM音频/ ),可以通过滤波进一步处理(见下一节)。 在过滤之后,帧被传递到编码器,编码器并输出编码的数据包。 最后,这些传递给复用器,将编码的数据包写入输出文件。
默认情况下,ffmpeg只包含输入文件中每种类型(视频,音频,字幕)的一个流,并将其添加到每个输出文件中。 它根据以下标准挑选每一个的“最佳”:对于视频,它是具有最高分辨率的流,对于音频,它是具有最多channel的流,对于字幕,是第一个字幕流。 在相同类型的几个流相等的情况下,选择具有最低索引的流。
您可以通过使用-vn / -an / -sn / -dn选项来禁用某些默认设置。 要进行全面的手动控制,请使用-map选项,该选项禁用刚描述的默认设置。
FFMPEG 可以使用下面的参数进行基本信息查询。例如,想查询一下现在使用的 FFMPEG 都支持哪些 filter,就可以用 ffmpeg -filters 来查询。详细参数说明如下:
查询编译器libfdk_aac的信息
FFMPEG 处理音视频时使用的命令格式与参数
ffmpeg 通过 -i 选项读取输任意数量的输入“文件”(可以是常规文件,管道,网络流,抓取设备等,并写入任意数量的输出“文件”。
原则上,每个输入/输出“文件”都可以包含任意数量的不同类型的视频流(视频/音频/字幕/附件/数据)。 流的数量和/或类型是由容器格式来限制。 选择从哪个输入进入到哪个输出将自动完成或使用 -map 选项。
要引用选项中的输入文件,您必须使用它们的索引(从0开始)。 例如。 第一个输入文件是0,第二个输入文件是1,等等。类似地,文件内的流被它们的索引引用。 例如。 2:3是指第三个输入文件中的第四个流
上面就是 FFMPEG 处理音视频的常用命令,下面是一些常用参数
首先通过下面的命令查看一下 mac 上都有哪些设备。
注意,桌面的输入对帧率没有要求,所以不用限制桌面的帧率。其实限制了也没用。
由于没有解码或编码,速度非常快,没有质量损失。 但是,由于许多因素,在某些情况下可能无法正常工作。 应用过滤器显然也是不可能的,因为过滤器处理未压缩的数据
上面的命令表式的是音频、视频都直接 copy,只是将 mp4 的封装格式转成了flv。
在编码之前,ffmpeg可以使用libavfilter库中的过滤器处理原始音频和视频帧。 几个链式过滤器形成一个过滤器图形。 ffmpeg区分两种类型的过滤器图形:简单和复杂。
请注意,某些滤镜会更改帧属性,但不会改变帧内容。 例如。 上例中的fps过滤器会改变帧数,但不会触及帧内容。 另一个例子是setpts过滤器。
复杂的过滤器图使用-filter_complex选项进行配置。 请注意,此选项是全局性的,因为复杂的过滤器图形本质上不能与单个流或文件明确关联。
-lavfi选项等同于-filter_complex。
一个复杂的过滤器图的一个简单的例子是覆盖过滤器,它有两个视频输入和一个视频输出,包含一个视频叠加在另一个上面。 它的音频对应是amix滤波器
添加文字水印
添加本地时间水印
>
一般我们在生成视频的 thumbnail 时,会直接截取首帧,当碰到视频首帧为黑帧的情况,导致 thumbnail 为一张全黑的,体验极差。
如何过滤掉视频中的黑帧,取得正常的视频帧。下面的 ffmpeg 语句可以帮助我们做到这件事:
blackframe 滤镜获取所有视频帧的黑色像素占比信息;metadata 滤镜过滤掉视频帧黑色像素占比超过50%的帧。
下面为两个滤镜的详细介绍:
接受参数:
0即检测所有帧
FFmpeg名称中的mpeg来自视频编码标准MPEG,而前缀FF是Fast Forward的首字母缩写。
目录
默认的编译会生成 4 个可执行文件和 8 个静态库。可执行文件包括用于 转码 、 推流 、Dump媒体文件的 ffmpeg 、用于播放媒体文件的 ffplay 、 用于获取媒体文件信息的 ffprobe ,以及作为简单流媒体服务器的 ffserver 。
8个静态库其实就是FFmpeg的8个模块,具体包括如下内容。
比如AAC编码,常见的有两种封装格式
AAC 的 bit stream filter 常常应用在 编码 的过程中。
与音频的AAC编码格式相对应的是视频中的 H264编码 ,它也有两种封装格式
FFmpeg中也提供了对应的 bit stream filter ,称 H264_mp4toannexb ,可以将MP4封装格式的H264数据包转换为annexb封装格式的H264数据 (其实就是裸的H264的数据)包。
H264 的 bit stream filter 常常应用于视频解码过程中。
ffmpeg 是进行媒体文件转码的命令行工具
ffprobe 是用于查看媒体 文件头信息的工具
ffplay 则是用于播放媒体文件的工具
1首先用ffprobe查看一个音频的文件
2输出格式信息format_name、时间长度duration、文件 大小size、比特率bit_rate、流的数目nb_streams等。
3以JSON格式的形式输出具体每一个流 最详细 的信息
4显示帧信息的命令如下:
5查看包信息的命令如下:
ffplay是以FFmpeg框架为基础,外加渲染音视频 的库libSDL来构建的媒体文件播放器。
业界内开源的 ijkPlayer 其实就是基于 ffplay 进行改造的播放器,当然其做了硬件解码以及很多兼容性的工作。
在 ffplay中音画同步的实现方式其实有三种。分别是
并且在 ffplay 中默认的对齐方式也是以 音频 为基准进行对齐的。
首先要声明的是,播放器接收到的视频帧或者音频帧,内部都会有 时间戳(PTS时钟) 来标识它实际应该在什么时刻进行展示。
实际的对齐策略如下:比较视频当前的播放时间和音频当前的播放时间
关键就在于音视频时间的比较以及延迟的计算,当然在比较的过程中会设 置一个 阈值(Threshold) ,若超过预设的阈值就应该做调整(丢帧渲染 或者重复渲染),这就是整个对齐策略。
ffmpeg 就是强大的媒体文件转换工具。它可以转换任何格式的媒体文件,并且还可以用自己的 AudioFilter 以及 VideoFilter 进行处理和编辑。
接下来介绍一个解码的实例,该实例实现的功能非常单一,就是把一个视频文件解码成单独的音频PCM文件和视频YUV文件。
AVFormatContext是API层直接接触到的结构体,它会进行格式的封 装与解封装。
该结构体包含的就是与实际的 编解码 有关的部分。
331 av_register_all
所以该函数的内部实现会先调用 avcodec_register_all 来注册所有configh里面开放的编解码器,然后会注册所有的 Muxer 和 Demuxer (也就是封装格式),最后注册所有的 Protocol (即协议层的东西)。
332 av_find_codec
这里面其实包含了两部分的内容:一部分是寻找 解码器 ,一部分是寻找 编码器 。
333 avcodec_open2
该函数是打开编解码器(Codec)的函数,无论是编码过程还是解码过程,都会用到该函数。
avformat_open_input
根据所提供的文件路径判断文件的格 式,其实就是通过这一步来决定使用的到底是哪一个 Demuxer 。
avformat_find_stream_info
该方法的作用就是把所有 Stream 的 MetaData 信息填充好。
av_read_frame
使用该方法读取出来的数据是 AVPacket 。
对于 音频流 ,一个 AVPacket 可能包含 多 个 AVFrame ,但是对于 视频流 ,一个 AVPacket 只包含 一 个 AVFrame ,该函数最终只会返回一个 AVPacket 结构体。
avcodec_decode
该方法包含了两部分内容:一部分是 解码视频 ,一部分是 解码音频 , 解码 是会委托给对应的解码器来实施的。
avformat_close_input
该函数负责释放对应的资源。
avformat_alloc_output_context2
该函数内部需要调用方法avformat_alloc_context来分配一个 AVFormatContext 结构体。
avio_open2
编码的阶段了,开发者需要将手动封装好的 AVFrame 结构体,作为 avcodec_encode_video 方法的输入,将其编码成为 AVPacket ,然后调用 av_write_frame 方法输出到媒体文件中。
本文参考 音视频开发进阶指南
项目源码地址 - FFmpegDecoder
ffmpeg是音视频处理的c库, 音视频在网络传输过程中,由于数据量大,所有需要进行压缩
压缩目的为了去除冗余信息,冗余信息分为:
1、空间冗余:图像相邻像素之间有较强的相关性
2、时间冗余:视频序列的相邻图像之间内容相似
3、 编码冗余:不同像素值出现的概率不同
4、 视觉冗余:人的视觉系统对某些细节不敏感
5、知识冗余:规律性的结构可由先验知识和背景知识得到
● 无损压缩(Winzip)
压缩前解压缩后图像完全一致
压缩比低
● 有损压缩(H264)
压缩前解压缩后图像不一致
压缩比高
利用人的视觉系统的特性(人眼能见的动画频率和图像细节有限制)
音视频压缩其实就是对音视频进行编码,
视频编码格式
音频编码格式
封装格式
流媒体协议
YUV ,是一种 颜色 编码 方法。常使用在各个视频处理组件中。 YUV在对照片或视频编码时,考虑到人类的感知能力,允许降低色度的带宽。
YUV是编译true-color颜色空间(colorspace)的种类,Y'UV,YUV, YCbCr , YPbPr 等专有名词都可以称为YUV,彼此有重叠。“Y”表示 明亮度 (Luminance、Luma),“U”和“V”则是[色度]
YUV格式有两大类:(平面格式)planar和(打包格式)packed。
1planar:先存储Y,然后U,然后V
2packed:yuv交叉存储
还有我们常说的YUV420sp与YUV420p。
YUV420sp: 一种two-plane模式,即Y和UV分为两个平面,U、V交错排列。
YUV420p: 先把U存放完后,再存放V。UV是连续的。
YUV420的数据大小为: 亮度(行×列) + V(行×列/4) + U(行×列/4)即:W H 3/2,
普遍的编码器都以接受planar的I420数据(YUV420P)
44的I420数据排列如下:
y1 y2 y3 y4
y5 y6 y7 y8
y9 y10 y11 y12
y13 y14 y15 y16
u1 u2 u3 u4
v1 v2 v3 v4
Android相机的采集的视频是NV21(YUV420sP), 也是YUV的格式 只不过U和V的交叉的。
y1 y2 y3 y4
y5 y6 y7 y8
y9 y10 y11 y12
y13 y14 y15 y16
u1 v1 u2 v2
u3 v3 u4 v4
在采集相机数据时需要把UV数据给转换成上面的 顺序。
I frame :帧内编码帧 ,I 帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。I帧可以看成是一个图像经过压缩后的产物。
P frame: 前向预测编码帧,通过充分将低于图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧;
B frame: 双向预测内插编码帧 ,既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧;
I frame:自身可以通过视频解压算法解压成一张单独的完整的。
P frame:需要参考其前面的一个I frame 或者B frame来生成一张完整的。
B frame:则要参考其前一个I或者P帧及其后面的一个P帧来生成一张完整的。
PTS:Presentation Time Stamp。PTS主要用于度量解码后的视频帧什么时候被显示出来
DTS:Decode Time Stamp。DTS主要是标识读入内存中的帧数据在什么时候开始送入解码器中进行解码。
在没有B帧存在的情况下DTS的顺序和PTS的顺序应该是一样的。
DTS主要用于视频的解码,在解码阶段使用。PTS主要用于视频的同步和输出在显示的时候使用。
如上图:I frame 的解码不依赖于任何的其它的帧而p frame的解码则依赖于其前面的I frame或者P frameB frame的解码则依赖于其前的最近的一个I frame或者P frame 及其后的最近的一个P frame
libavformat
用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能;音视频的格式解析协议,为 libavcodec 分析码流提供独立的音频或视频码流源。
libavcodec
用于各种类型声音/图像编解码;该库是音视频编解码核心,实现了市面上可见的绝大部分解码器的功能,libavcodec 库被其他各大解码器 ffdshow,Mplayer 等所包含或应用。
libavfilter
filter(FileIO、FPS、DrawText)音视频滤波器的开发,如水印、倍速播放等。
libavutil
包含一些公共的工具函数的使用库,包括算数运算 字符 *** 作;
libswresample
原始音频格式转码。
libswscale
(原始视频格式转换)用于视频场景比例缩放、色彩映射转换;图像颜色空间或格式转换,如 rgb565,rgb888 等与 yuv420 等之间转换。
音视频解5封装流程:
ffmpeg解码流程:
cuvid 与 VDPAU 是平级的东西,不能拿来直接使用,使用成本太大
note:
note
Note: For Video Codec SDK 70 and later, NVCUVID has been renamed to NVDECODE API
这是我第一次使用的方式,模仿 cpu 上软解码(获取视频帧,并存储为bmp格式,经验原则,这种方式最容易想到)
运行结果:
失败,bad src img pointers
运行结果如下图所示:
问题原因:
gpu 不支持 sws_scale + AV_PIX_FMT_CUDA-> AV_PIX_FMT_BGR24 的直接像素转换方式,那么 能否直接在gpu中直接转化 AV_PIX_FMT_CUDA 为 AV_PIX_FMT_BGR24呢
如果可以直接实现,性能会有很大提升,因为减少了device->host 的数据传输,且gpu多核心并行处理,肯定比cpu处理性能要强悍。
运行结果:
失败,像素没对齐,只有亮度
运行结果如下图所示:
![预先设置内存中frame目标像素格式为 AV_PIX_FMT_BGR24]
问题原因:
如下图所示:
所以gdb了下源码,发现src->frame->format 转换为 dst->frame->format 的受限范围很小,然后找出了 av_hwframe_transfer_get_formats 支持的formats,
调试过程如下所示:
gdb -tui hw_decode_cuvid (-tui 支持查看源码)
在调用 av_hwframe_transfer_data() 函数处打上断点,且设置程序运行所需参数
run 程序,step 进入函数调用栈
n 单步运行,函数调用至 transfer_data_alloc()
发现 av_hwframe_transfer_get_formats()函数
更改 dst->format 的值为<0的值,并打印支持的像素转换列表
可以看到只支持 gpu 硬件像素编码格式->AV_PIX_FMT_NV12 的转换
运行结果:
成功,如下图所示:
以上就是关于ffmpeg 命令大全全部的内容,包括:ffmpeg 命令大全、c#中如何提取视频文件中的帧啊、过滤视频中的黑帧(生成视频thumbnail时,跳过黑帧)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)