查找编解码器
avcodec_find_decoder
和avcodec_find_encoder
主要是查找 FFmpeg 的解码器和编码器。
avcodec_find_decoder 和 avcodec_find_encoder 主要是利用 AVCodecID 来查找编解码器。 其实质是遍历AVCodec 链表并且获得符合AVCodecID的元素。
初始化IO上下文
1 | int avio_open2(AVIOContext **s, const char *url, int flags, |
avio_open2 主要实现创建并初始化一个 AVIOContext,用于访问由 url 指定文件。
各个参数的含义如下:
AVIOContext **s
:函数调用成功后,创建并初始化该AVIOContext
结构体。const char *url
:输入输出协议的地址。int flags
:打开地址的方式(只读、只写、读写)。AVIO_FLAG_READ/AVIO_FLAG_WRITE/AVIO_FLAG_READ_WRITE.const AVIOInterruptCB *int_cb
:调用函数。AVDictionary **options
:一般为NULL。
与avio_open2
相似的还有avio_open
函数,avio_open
会调用avio_open2
,并将 int_cb 和 options 设置为 NULL。
avio_open2
的调用函数关系如下:
初始化编解码上下文
1 | int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); |
avcodec_open2
函数实现的功能为利用给定的AVCodec
结构初始化AVCodecContext
结构。
函数参数说明:
avctx
:需要初始化的context.codec
options
- 返回值:如果返回0,正确。失败则返回负数。
该函数利用给定的AVCodec
结构初始化AVCodecContext
结构,在使用该函数之前,AVCodecContext
必须已经用avcodec_alloc_context3()
函数分配出来。
AVCodec
结构在使用该函数之前,由avcodec_find_decoder_by_name``avcodec_find_encoder_by_name
avcodec_find_decoder
或avcodec_find_encoder
提前得到。
注意,在正式解码之前(比如使用avcodec_decode_video2()
之前),必须调用avcodec_open2
函数。
avcodec_open2
的逻辑非常简单,首先是进行一些参数检测、之后调动AVCodec
的init函数。大概步骤如下:
- 各种函数参数检测。
- 各种结构体分配内存。
- 将输入的
AVDictionary
形式的选项设置到AVCodecContext
。 - 其他一些零散的检查,检查输入参数是否符合编码器的要求。
- 调用
AVCodec
的init函数初始化具体的解码器。
此处重点分析调用AVCodec
的init函数处。 以 HEVC 解码器为例。
读取压缩数据包
1 | int av_read_frame(AVFormatContext *s, AVPacket *pkt); |
av_read_frame
函数的作用是返回文件中保存的数据。它会文件中保存的数据分成不同的帧, 每次调用都会返回一帧。注意,该函数不会忽略帧与帧之间无效数据(非帧数据),目的是给解码器 最多的信息用于解码。
如果pkt->buf
是 NULL,包直到下一次调用av_read_frame
或avformat_close_input
时都是有效的。 不需要时,包必须通过av_free_packet
释放。对于视频,packet
只包含一帧;对于音频,如果每帧有固定大小(如 PCM 或 ADPCM 数据), packet
可以包含多个音频帧(必须是整数帧),如果音频帧大小可变(如MPEG 音频),它只能包含一帧数据。
pkt->pts
、pkt->dts
、pkt->duration
都是以AVStream.time_base_units
为单位的。 如果视频格式里包含 B 帧,pkt->pts
可以是AV_NOPTS_VALUE
,因此如果不解压缩数据,最好查看pkt->dts
。
如果函数返回0,正确;小于0,则为到文件尾或出错。
函数调用关系:
av_read_frame
函数会判断在未解码缓存中是否有数据,如果有数据则调用read_from_packet_buffer
。
提取流信息
1 | int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); |
avformat_find_stream_info
主要是读媒体文件的包(packets),然后从中提取出流的信息。 对于没有头部信息的文件格式尤其有用,比如MPEG
。文件的逻辑位置不会被改变,读取出来 的包会被缓存起来供以后处理。
返回值:>=0–>OK,或出错返回AVERROR_xxx
注意,该函数并不保证能够打开所有的 codec,因此将options 设置为非NULL用于返回一些信息是非常好的行为。
调用关系: