本文只是整理了该函数的大概轮廓。
avformat_open_input 初始化AVFormatContext结构体对象,主要有三个功能:
AVIOContext 结构体对象初始化(pb); AVInputFormat 结构体对象初始化(iformat);
AVStream 结构体对象初始化(streams)
摘录主要功能点
avformat_open_input (AVFormatContext **ps, const char *filename,
AVInputFormat *fmt, AVDictionary **options){
AVFormatContext *s = *ps;
s = avformat_alloc_context(); //实现avformatcontext对象的初始化,变量的默认值赋值
init_input(s, filename, &tmp); //实现 s中pb(AVIOContext)和 iformat(AVInputFormat)的构建
s->iformat->read_header(s); //实现s中sreams(AVStream)的构建
}
1. AVIOContext 结构体对象初始化
avformat_alloc_context(){ //对代码进行了整理,主要是整理逻辑 (libavformat/option.c)
AVFormatContext *ic;
ic = av_malloc(sizeof(AVFormatContext));
ic->av_class = &av_format_context_class; //av_format_context_class为静态变量(AVClass),
//option指向 option_tables.h中的静态变量avformat_options
ic->io_open = io_open_default;
ic->io_close = io_close_default;
av_opt_set_defaults(ic);
}
av_opt_set_defaults()调用avformat_options中的默认值给ic中的变量赋值
io_open_default为打开文件或者url的函数,在该函数中会构造ic的pb;该函数会被init_input调用,流程如下:
init_input(AVFormatContext *s, const char *filename, AVDictionary **options){ //摘录主要流程(libavformat/utils.c)
s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options);//构造s的pb(AVIOContext)
av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->format_probesize);//构造s的iformat(AVInputFormat)
}
s->io_open就是io_open_default函数 //libavformat/options.c
io_open_default(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options) {
ffio_open_whitelist(pb, url, flags, &s->interrupt_callback, options, s->protocol_whitelist, s->protocol_blacklist);
}
ffio_open_whitelist(AVIOContext **s, const char *filename, int flags, ...){ //libavformat/aviobuf.c)
URLContext *h;
ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist, blacklist, NULL);//构造h对象 (libavformat/avio.c)
ffio_fdopen(s, h);//根据h构造s对象,至此完成AVIOContext的构造 libavformat/aviobuf.c)
}
2. AVInputFormat 结构体对象初始化(iformat);
init_input(AVFormatContext *s, const char *filename, AVDictionary **options){ //摘录主要流程(libavformat/utils.c)
s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options);//构造s的pb(AVIOContext)
av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->format_probesize);//构造s的iformat(AVInputFormat)
}
av_probe_input_buffer2(AVIOContext *pb, ff_const59 AVInputFormat **fmt, const char *filename, ...){ //(libavformat/format.c)
AVProbeData pd = { filename ? filename : "" };
for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt; probe_size = FFMIN(probe_size << 1,
FFMAX(max_probe_size, probe_size + 1))) {
//修改pd缓存大小
*fmt = av_probe_input_format2(&pd, 1, &score);
}
}
AVInputFormat *av_probe_input_format3(ff_const59 AVProbeData *pd, int is_opened, int *score_ret){ //(libavformat/format.c)
//便利所有的AVInputFormat,根据读取的文件头,比较extensions, mini_type获取一个最高分,就是选用的AVInputFormat
while ((fmt1 = av_demuxer_iterate(&i))) {
if (fmt1->read_probe) {
score = fmt1->read_probe(&lpd);
if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) { //这个一项基本不用
//.....
}
} else if (fmt1->extensions) { //这个一项基本不用
if (av_match_ext(lpd.filename, fmt1->extensions))
score = AVPROBE_SCORE_EXTENSION;
}
if (av_match_name(lpd.mime_type, fmt1->mime_type)) {
score = AVPROBE_SCORE_MIME;
}
if (score > score_max) {
score_max = score;
fmt = (AVInputFormat*)fmt1; //根据分数大小确定 至此确定AVInputFormat
} else if (score == score_max)
fmt = NULL;
} // end while
}
3. AVStream 结构体对象初始化(streams)
s->iformat->read_header(s); // 比如ts流文件,调用(libavformat/mpegts.c)中的mpegts_read_header
mpegts_read_header(){
//该函数会获取streams信息
if (s->iformat == &ff_mpegts_demuxer) {
seek_back(s, pb, pos);
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
handle_packets(ts, probesize / ts->raw_packet_size); //该函数会对streams赋值,完成streams的检索
/* if could not find service, enable auto_guess */
ts->auto_guess = 1;
av_log(ts->stream, AV_LOG_TRACE, "tuning done\n");
s->ctx_flags |= AVFMTCTX_NOHEADER;
}
}