FFMPEG函数之avformat_open_input

来源:互联网 发布:it职业培训 编辑:程序博客网 时间:2024/04/28 10:51

在进行输入和输出转码的过程中,会使用一个函数:

int avformat_open_input(AVFormatContext **ps, const char *filename,

                        AVInputFormat *fmt, AVDictionary **options)

其目的是打开流,并通过filename来初始化AVFormatContext中的AVIOContext *pb结构体数据。用来实现对数据进行读取(数据可能来源于file,memfifosocket)。到底是怎样的呢?下面我们来具体分析分析源码:

 

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解复用器,并通过demuxread_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,看这儿应该可以想起当初初始化savformat_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成员的申请和初始化工作。至此,完成了该函数的所有功能。

原创粉丝点击