
FFmpeg 代码 (opens new window)目录结构:

libavformat 主要是用来做封装格式处理的模块。
avformat_version:FFmpeg 版本信息avformat_configuration:FFmpeg 编译配置信息avformat_license:FFmpeg 许可证信息许可法律风险
FFmpeg 本身是 LGPL 的,但是 FFmpeg 可以引入其他第三方库,比如 libfdkaac 是 nonfree 的,就有可能存在专利收费的法律风险。
前处理部分,主要包含网络初始化、模块遍历、申请上下文空间、打开文件,还有分析音视频流等操作。
avformat_network_init 和 avformat_network_deinit:初始化网络模块 和 撤销网络模块初始化av_muxer_iterate 和 av_demuxer_iterate:muxer 和 demuxer 的遍历接口avformat_alloc_context 和 avformat_free_context:申请和释放 AVFormatContext 上下文avformat_new_stream:创建新的 AVStreamav_stream_add_side_data 和 av_stream_get_side_data:添加和获取 AVStream 的附加数据avformat_alloc_output_context2:申请用来输出文件的 AVFormatContext,可以通过 avformat_free_context 释放avformat_open_input 和 avformat_close_input:打开 AVInputFormat 并挂在 AVFormatContext 上,会调用 avformat_alloc_contextav_find_input_format:根据传入的 short_name 查找 AVInputFormatav_find_best_stream:查找最佳的音视频流avformat_find_stream_info:分析音视频流信息可以通过 probesize、analyzeduration 来设置读取的音视频数据的阈值,avformat_find_stream_info 里面也会遍历这个阈值,所以通过设置 probesize 和 analyzeduration 也可以节省一些时间。
av_read_frame:从 AVFormatContext 中读取 AVPacketavformat_seek_file:在 AVFormatContext 中查找 AVPacket,如拖动进度条avformat_flush:清空 AVFormatContext 中的缓存avformat_write_header:主要用在“写”操作的开头部分,通常指传输协议的开始,写封装格式头部avformat_init_output:用来做容器格式初始化部分的操作,如打开文件,或者有一些容器格式内部的信息需要初始化的时候av_interleaved_write_frame:支持在写入 AVPacket 的时候,根据 dts 时间戳交错写入数据av_write_frame:不按照交错的形式存储 AVPacket,不过在写入文件的时候是直接写入到磁盘,不会有 bufferav_write_trailer:写数据到封装容器的收尾部分
AVIO 接口,主要是为了方便读、写内容时做一些字节对齐与大小端定义的操作。
avio_find_protocol_name:获取字符串协议名avio_alloc_context:申请 AVIOContext 句柄,并且可以在申请的时候注册 read_packet、write_packet 与 seek 回调,然后可以将 AVIOContext 句柄挂载到 AVFormatContext 的 pb 上面avio_skip:跳过指定字节数avio_seek:跳转到指定位置avio_tell:文件读写之后当前的文件位置avio_size:获取当前写入内容的大小avio_feof:判断是否读到文件末尾avio_flush:将内容刷到目标文件avio_open_dyn_buf、avio_get_dyn_buf、avio_close_dyn_buf:写入文件需要先临时放在内存中,最后按照自己的计划将内容刷到文件中avio_close 与 avio_closep:释放申请的资源avio_open 和 avio_open2:打开 FFmpeg 的输入输出文件
FFmpeg 提供的命令行支持很多参数,这些参数不单单是提供给命令行用户的,API 用户也可以使用。
可以通过 AVDictionary 或者 AVOption 来设置参数,这两个 API 系列主要用来设置操作目标的 format、codec、protocol 的参数,最终达到与命令行使用参数一样的效果。
avcodec_find_encoder、avcodec_find_encoder_by_name av_codec_is_encoderavcodec_find_decoder、avcodec_find_decoder_by_name av_codec_is_decoderavcodec_alloc_context3 申请 AVCodecContext 并建立关联 avcodec_free_context 释放avcodec_open2avcodec_send_packet、avcodec_receive_frameavcodec_send_frame、avcodec_receive_packetAVPacket AVPacket:av_packet_alloc av_new_packetAVPacket:av_packet_free
avformat_open_input、avformat_find_stream_info 来打开输入文件,并根据输入文件中的音视频流信息建立音视频流,也就是 AVStreams。avformat_alloc_output_context2、avformat_new_stream 和 avformat_write_header 打开输出文件,并建立音视频流,输出文件会用到 AVOutputFormat,并建立封装格式操作的 AVFormatContext,作为操作上下文的结构体,并且会尝试写入输出文件的封装格式头部信息。av_read_frame 函数,从输入文件中读取 AVPacket 音视频数据包,还会使用 av_interleaved_write_frame 函数,将读取到的音视频数据包写入输出文件。av_write_trailer 函数,在关闭输出文件之前做写封装收尾工作。使用 avformat_free_context 函数关闭输出文件,并释放因操作输出文件封装格式申请的资源。最后使用 avformat_close_input 关闭输入文件并释放相关的资源。日常操作时,做 remux 主要还是用于收录一些音视频内容的场景中,用得更多的还是编码或者转码的操作。因为音视频的编码数据格式比较多,需要统一转成相同的编码,即将输入的音视频内容转成统一规格输出的场景,比收录场景更常见。
