致敬大神——本文内容来自雷霄骅的博客。总结此文主要是对 ffmpeg的细节有个深入的理解。
首先回顾一下ffmpeg中最重要的几个结构体:
AVFormatContext(统领全局,主要存储视音频封装格式中包含的信息)
|------AVInputFormat(存储输入视音频使用的封装格式)
|------AVOutputFormat(存储输出音视频使用的封装格式)
|------AVIOContext(处在协议层)
| |---------URLContext(存储视音频使用的协议的类型以及状态)
| |--------- URLProtocol(存储输入视音频使用的封装格式)
|------AVStream(存储一个视频/音频流的相关数据)
|---------AVCondecContext(存储该视频/音频流使用解码方式的相关数据)
|---------AVCodec(视频/音频对应的解码器)
下面来简要
1、avio_open2()这个函数主要做两件事:
a ffurl_open()
b ffio_fdopen()
①初始化AVIOContext中的URLContext
②根据URLContext初始化AVIOContext,并打开输入输出口。注:在往输出端写数据之前,一定要先avio_open2()打开输出口。
2、avformat_open_input()这个函数可谓是ffmpeg整个流程的灵魂了。
这个函数中又分为两个部分:
1)init_input()--------完成基本的初始化,得到相应的AVInputFormat,至于这个AVInputFormat,如果有指定AVInputFormat参数传进来,就直接使用这个AVInputFormat,不然就需要去probe输入音视频流数据的格式,需要花费一些时间。
①av_probe_input_format2()
②avio_open2 ()
③av_probe_input_buffer2()
2)iformat==>read_headr()==>avformat_new_stream() --------------创建AVStream
总结:该函数影响了AVFormatContext中的AVInputFormat、AVIOContext、AVStream。主要是完成了对输入的AVFormatContext中的AVInputFormat的初始化,对AVIOContext打开输入控制,以及创建AVStream。
3、avformat_find_stream_info():主要是给输入AVFormatContext的AVStream赋值
①对成员变量赋值:主要是比特率、时长、时间戳等
②find_decoder()
③avcodec_open2()
④read_frame_internal() :读取一帧压缩码流数据
⑤try_decode_frame():尝试解压④中解压出来的码流,得到码流的信息。
4、avformat_alloc_output_context2():
如果指定了AVOutputFormat的话,直接用指定的这个AVOutputFormat给输出AVFormatContext中的AVOutputFormat赋值。如果没有指定AVOutputFormat的话,就要通过传进来的输出文件名称或者输出格式名称来猜测(用格式名称来猜测的话速度会比较快,因为ffmpeg源码内部通过名称来猜测设置了一个评分机制,直接给正确的格式名称就像参数给"flv"、"rtp"诸如此类的,猜中的概率会更大,也就更快);
①avformat_alloc_context()-----------------------给一个输出AVFormatContext分配内存
②av_guess_format()-------------------------------给AVFormatContext中的AVOutputFormat初始化
5、avformat_new_stream():
首先调用av_mallocz()为AVStream分配内存。
接着给新分配的AVStream的各个字段赋上默认值。
然后调用了另一个函数avcodec_alloc_context3()初始化AVStream中的AVCodecContext。
6、avcodec_copy_context()与avcodec_parameters_copy()
老版ffmpeg是用AVCondecContext来存储AVCodec的上下文,但是在新版ffmpeg中,使用avcodec_copy_context()会报错,所以需要使用avcodec_parameters_copy()来copyAVCodec的上下文。