您的位置:首页 > 运维架构

FFMPEG函数之avformat_open_input

2017-11-07 14:11 519 查看
在进行输入和输出转码的过程中,会使用一个函数:
int avformat_open_input(AVFormatContext **ps, const char *filename,
                        AVInputFormat *fmt, AVDictionary **options)
其目的是打开流,并通过filename来初始化AVFormatContext中的AVIOContext *pb结构体数据。用来实现对数据进行读取(数据可能来源于file,mem,fifo,socket等)。到底是怎样的呢?下面我们来具体分析分析源码:
 
avformat_open_input
→avformat_alloc_context:为AVFormatContext分配空间,并初始化。
→avformat_get_context_defaults:这个是里面比较重要的一个函数,设置的AVFormatContext默认参数,记住在这里已经初始化了AVFormatContext中的io_open()和io_close()函数指针了,这儿很重要,因为后面在后面会用到这儿的函数。这个等我们后面用到的时候在分析。
→init_input:这儿很重要,打开文件并探测流的格式。在代码里面可以看到,如果已经初始化了AVIOContext *pb,这直接调用av_probe_input_buffer2来探测url的格式。否则会调用av_probe_input_format2进行源类型进行分析(主要是初始化AVIOContext
*pb)。那我们来看看是如何来初始化pb的呢。
→av_probe_input_format2:
→av_probe_input_format3:在这里面会遍历注册的所以的demux解复用器,并通过demux的read_probe()函数来探测出流的格式。
下面我们来详细分析其过程:
If(fmt1->read_probe)如果解复用存在该函数,则使用该函数来分析。我们随意取一个demux看看,它是怎样来实现该read_probe的呢?以ff_rtsp_demuxer为例,rtsp_probe(av_strstart(p->filename,
"rtsp:", NULL)))可以看出其仅仅使用url的头部进行匹配。如果匹配成功则返回maxsocore(100分),这儿初始化了AVFormatContext中的AVInputFormat
iformat参数;
接下来调用了s->io_open,看这儿应该可以想起当初初始化s的avformat_get_context_defaults函数,因为那里初始化了该函数指针。我们看看到底干了些什么呢?io_open实际调用过程如下:
io_open_default

{
      ffio_open_whitelist
      {
           ffurl_open_whitelist
           {
               ffurl_alloc
              {
                  url_find_protocol:
                  {
                       ffurl_get_protocols 
                       {
                               返回了URLProtoco的一个数组集合。Ffmpeg支持的urlprotocol都添加在此数组中。
                             根据文件名与下面获取的urlprotocol数组进行匹配。找到合适的URLProtocol。
                       }
                      url_alloc_for_protocol
                       {
                              这里完成了URLContext内存的分配
                             初始化(URLContext 中含有URLProtocol *prot的成员)。
                       }
                 }
             }//end  ffurl_alloc
        }//end  ffurl_open_whitelist
        ffio_fdopen(AVIOContext **s, URLContext *h)
        {
          *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE,

                            internal, io_read_packet, io_write_packet, io_seek);
          这里申请了AVIOContext 的内存,并初始化了AVIOContext 的指针函数。
          这个函数执行完后,输入的参数s即已有值了。这里AVFormatContext中的AVIOContext *pb已经初始化完毕。
        }
    }//ffio_open_whitelist

}//io_open_default

接下来,函数调用了av_probe_input_buffer2,主要是获取到iformat的空间以及初始化其相关参数,在上面已经分析过其过程了。

综上:该函数主要完成了申请并初始化了AVFormatContext,如果用户没有指定AVIOContext则先使用io_open来申请相应空间并初始化成员AVIOContext(实质是根据filename找到相应的URLProtocol结构,以后的读取和写入过程,实际是用过该URLProtocol结构进行的)。当得到相应的AVIOContext
*pb后,调用av_probe_input_buffer2完成AVFormatContext 中的iformat成员的申请和初始化工作。至此,完成了该函数的所有功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ffmpeg 流媒体