目录
FFmpeg 目录中包含了 FFmpeg 库代码目录、构建工程目录、自测子系统目录等,具体内容如下:
现在你知道 FFmpeg 的源代码目录中都包含了哪些内容,在之后使用 FFmpeg 的 API 做开发遇到问题时,就可以通过查看源代码来了解更多、更详细的内部实现了。
从 FFmpeg 的目录结构中可以看出,libavformat 主要是用来做封装格式处理的模块,如果不做转码,只做切片或者封装格式转换的话,基本上用 AVFormat 模块就可以,下面我们来看一下 AVFormat 模块都有哪些常用接口提供给我们使用。
avformat_version、avformat_configuration、avformat_license 这三个接口都是用来调试的,确定使用的 FFmpeg 版本、编译配置信息以及 License。因为 FFmpeg 本身是 LGPL 的,但是FFmpeg 可以引入其他第三方库,比如 libfdkaac 是 nonfree 的,就有可能存在专利收费的法律风险。
如果引入了 libx264 这样的编码器,FFmpeg 会自动切换成 GPL 的 License,这个时候如果你想要基于 FFmpeg 做定制或者开发,就需要注意 GPL 的 License 法律风险,相关情况最好还是咨询一下开源 License 法律援助律师,尽量避免给自己的项目和公司带来不必要的麻烦。
GPL 是 GNU 公共许可证的缩写。它通常会具有 “传染性”,当某一项目使用了 GPL 下的软件部分的话,那么该项目将被 “感染”变成了 GPL 协议下产品,也就是你需要将其开源和免费。LGPL 是 GNU 宽松公共许可证的缩写,它是 GPL 的一个为主要为类库使用设计的开源协议。和 GPL 不同,LGPL 允许商业软件通过类库引用方式使用 LGPL 类库而不需要开源商业软件的代码。——关于开源许可 GPL 与 LGPL
当我们做音视频内容处理的时候,首先接触到的应该是 AVFormatContext 模块相关的操作,也就是我们这里说的 AVFormat 部分,但是操作 AVFormat 的时候,会有一个前处理部分,主要包含网络初始化、模块遍历、申请上下文空间、打开文件,还有分析音视频流等操作。下面我们逐个了解一下 AVFormat 前处理部分的接口与作用。
我们可以通过 probesize、analyzeduration 来设置读取的音视频数据的阈值,avformat_find_stream_info 里面也会遍历这个阈值,所以通过设置 probesize 和 analyzeduration 也可以节省一些时间。
如果有多个类似 AAC 或者 H264 这样的 codec 的话,avformat_find_stream_info 内部会使用最先遍历到的 codec,其实我们可以在使用 avformat_find_stream_info 之前指定解码器,预期的结果会更准确一些。
看完 AVFormat 前处理部分的操作,接下来我们进入 AVFormat 读写处理的部分。
- AVSEEK_FLAG_BACKWARD //往回seek
- AVSEEK_FLAG_BYTE //以字节数的方式seek
- AVSEEK_FLAG_ANY //可seek到任意帧
- AVSEEK_FLAG_FRAME //以帧数量的方式seek
写 MP4 文件有很多 Option,可以通过 ffmpeg -h muxer=mp4 看到生成 MP4 的一些列参数,也就是 Option。
我们在存储音视频数据的时候,如果是顺序读取音视频数据的话,音视频数据交错存储比较好,因为这样可以给内存、硬盘或者网络节省很多开销。
FFmpeg 中有很多重要的模块,比如 AVFormat 模块、AVcodec 模块、AVfilter 模块等。其中 AVFormat 是用来做封装格式处理的模块。这个模块的内部提供了很多常用的接口,比如前处理部分的 avformat_find_stream_info 等接口,读写处理部分的 avformat_write_header、av_interleaved_write_frame 等接口,了解这些接口的用途和可能出现的问题及解决办法,可以让我们在实践中更好地使用它们去做容器封装和解封装方面的操作。
关于 AVFormat 模块中 API 接口更多的使用方式,比如说参数相关的内容,你还需要多看一看 avformat.h 头文件中的注释和参数说明。如果你还是掌握不住这些接口的使用方式的话,也可以根据我的建议,先把源代码下来,去看一下 API 里实现的过程来加深理解。
我们介绍最后一个接口 av_write_trailer 的时候,提到它支持把 MP4 的 moov 移动到文件的头部,在 FFmpeg 的命令行参数里面使用的是 -movflags faststart,那么如果我用 API 的话,需要在哪个接口里面传递这个参数呢?