0%

FFmpeg基本API:源码分析

查找编解码器

avcodec_find_decoderavcodec_find_encoder 主要是查找 FFmpeg 的解码器和编码器。

avcodec_find_decoder 和 avcodec_find_encoder 主要是利用 AVCodecID 来查找编解码器。 其实质是遍历AVCodec 链表并且获得符合AVCodecID的元素。

初始化IO上下文

1
2
int avio_open2(AVIOContext **s, const char *url, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options);

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的调用函数关系如下:

img

初始化编解码上下文

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_decoderavcodec_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_frameavformat_close_input时都是有效的。 不需要时,包必须通过av_free_packet释放。对于视频,packet只包含一帧;对于音频,如果每帧有固定大小(如 PCM 或 ADPCM 数据), packet可以包含多个音频帧(必须是整数帧),如果音频帧大小可变(如MPEG 音频),它只能包含一帧数据。

pkt->ptspkt->dtspkt->duration都是以AVStream.time_base_units为单位的。 如果视频格式里包含 B 帧,pkt->pts可以是AV_NOPTS_VALUE,因此如果不解压缩数据,最好查看pkt->dts

如果函数返回0,正确;小于0,则为到文件尾或出错。

函数调用关系:

img

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用于返回一些信息是非常好的行为。

调用关系:

img

欢迎关注我的其它发布渠道