avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
首先声明几个变量,
AVFormatContext* s=*ps ;
AVDictionary* tmp=NULL;
假设 调用参数f分别为 ps filename NULL NULL
- 首先调用 avformat_alloc_context(void)
在函数里 声明一个AVFormatContext* ic
给ic开辟大小为sizeof(AVFormatContext)的内存空间 用av_malloc(size_t)
然后给ic赋默认初始值:先将ic->av_class =&av_format_context_class av_format_context_class为静态全局变量,存放在、libavformat里的Options.c中 值为:
static const AVClass av_format_context_class = {
.class_name = "AVFormatContext",.item_name = format_to_name,
.option = options, options为静态全局变量 也存放在libavformat里的options_table.h中 是AVOption结构体数组的首地址
.version = LIBAVUTIL_VERSION_INT,.child_next = format_child_next,.child_class_next = format_child_class_next,.category = AV_CLASS_CATEGORY_MUXER,.get_category = get_category,};
最后调用av_opt_set_defaults2(s, 0, 0);使得ic->av_class里的 指针option指向options数组的最后一个有效值,即倒数第二个值,options数组都是以NULL结尾的。
就是说avformat_alloc_contexth 主要是编辑AVClass类型 av_class,而其他指针都还没赋值。
2. 然后判断 fmt和options,
if(fmt)
s->iformat = fmt;
if(options)
av_dict_copy(&tmp,options);
若不是自定义,但是一般都会是NULL
3. 然后调用av_opt_set_dict(s,&tmp);
作用是将AVDictionary(字典)tmp中的所有选项设置进传入的AVFormatContext(文件格式上下文),但是此处tmp=NULL,函数
会直接返回0
4. 然后调用 if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
作用是建立并根据文件名 初始化AVFormatContext中的AVIOContext 和 AVInputFormat的变量指针。
5. 然后若输入文件名是需要数字在里面的,测试文件名....待研究
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(filename)) {
ret = AVERROR(EINVAL);
goto fail;
}
}
6. 然后给AVFormatContext里的 filename赋值为输入文件名,duration 和 start_time赋值 AV_NOPTS_VALUE ,
s->duration = s->start_time = AV_NOPTS_VALUE;
av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
7. s->iformat->priv_data_size已经在 init_input中的av_open2函数里被赋值,由大小等于URLProtocol里的priv_data_size,而它等 于对应协议的协议头文件结构体的大小。由注册时得到。s->iformat->priv_class同理。 不过av_opt_set_defaults最后返回write_number()里 的 将priv_data指向了一个整数,意思不是很清楚。
if (s->iformat->priv_data_size > 0) {if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {ret = AVERROR(ENOMEM);goto fail;}if (s->iformat->priv_class) {*(const AVClass**)s->priv_data = s->iformat->priv_class;av_opt_set_defaults(s->priv_data);if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)此处tmp还是为NULL,所以直接返回0;goto fail;}}
8. /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
if (s->pb)
ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
9. 每个iformat的read_header都是在注册时赋值好的,对应于相应的输入结构,注册时 对应相应的 demuxer(分离音视频的作用,
分离器是把流中的视频和音频数据分离开来,分别进行播放。不同协议的流有不同的分离器
)。 s->nb_stream就算不给它赋值,在开辟s的空间时,就已经被系统默认为0了,在read_header中会调用 avformat_new_stream(s,NULL);
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
if ((ret = s->iformat->read_header(s)) < 0)
goto fail;
10. 这个还不大了解
if (id3v2_extra_meta) {if (!strcmp(s->iformat->name, "mp3")) {if((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)goto fail;} elseav_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n"); ff_id3v2_free_extra_meta(&id3v2_extra_meta);
11.
avformat_queue_attached_pictures(s);
12. 给AVFormatContext的data_offse和raw_packet_buffer_remaining_sizet赋值.
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
s->data_offset = avio_tell(s->pb)
s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE
13. 最后options和tmp还是=NULL 将s赋值给*ps
if (options) {av_dict_free(options);*options = tmp;}*ps = s;return 0;