懒人李冰

记录我的生活、学习

FFMPEG源码分析:avio_open2

avio_open2 主要实现创建并初始化一个 AVIOContext,用于访问由 url 指定文件。

avio_open2 声明和定义

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

各个参数的含义如下:

  • 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 调动关系

avio_open2的调用函数关系如下:

avio_open2 源码分析

avio_open2函数的定义如下:

avio_open2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int avio_open2(AVIOContext **s, const char *filename, int flags,
               const AVIOInterruptCB *int_cb, AVDictionary **options)
{
    URLContext *h;
    int err;

    err = ffurl_open(&h, filename, flags, int_cb, options);
    if(err < 0)
        return err;

    er = ffio_fdopen(s, h);
    if(err < 0){
        ffurl_close(h);
        return err;
    }

    return 0;
}

avio_open2调用的两个函数,ffurl_openffio_fdopenffurl_open用于初始化URLContext,ffio_fdopen用于根据URLContext初始化AVIOContext

ffurl_open 函数

其中的ffurl_open函数定义如下:

ffurl_open
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int ffurl_open(URLContext **puc, const char *filename, int flags,
               const AVIOInterruptCB *int_cb, AVDictionary **options)
{
    int ret = ffurl_alloc(puc, filename, flags, int_cb);
    if(ret < 0)
        return ret;

    if(options && (*puc)->prot->priv_data_class &&
       (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
        goto fail;

    if((ret = av_opt_set_dict(*puc, options)) < 0)
        goto fail;

    ret = ffurl_connect(*puc, options);
    if(!ret)
        return 0;

fail:
    ffurl_close(*puc);
    *puc = NULL;
    return ret;
}

ffurl_open主要调用两个函数ffurl_allocffurl_connect

ffurl_alloc 函数

ffurl_alloc用于查找合适的URLProtocol,并创建一个URLContext;

ffurl_alloc
1
2
3
4
5
6
7
8
9
int ffurl_alloc(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb)
{
    URLProtocol *p = NULL;
    ……
    p = url_find_protocol(filename);
    if(p)
        return url_alloc_for_protocol(puc, p, filename, flags, int_cb);
    ……
}

ffurl_alloc调用两个函数:url_find_protocol根据文件路径查找合适的URLProtocol,url_alloc_for_protocol为查找到的URLProtocol创建URLContext

ffurl_connect
1
2
3
4
5
int ffurl_connect(URLContext *uc, AVDictionary **options)
{
    int err = uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options):
        uc->prot->url_open(uc, uc->filename, uc->flags);
}

ffurl_connect 函数

ffurl_connect用于打开获得的URLProtocol.如果以UDP为例的话,它的URLProtocol定义如下,打开URLProtocol时,会调用到udp_open函数。

ff_udp_protocol
1
2
3
4
5
6
7
8
9
10
11
URLProtocol ff_udp_protocol = {
    .name                = "udp",
    .url_open            = udp_open,
    .url_read            = udp_read,
    .url_write           = udp_write,
    .url_close           = udp_close,
    .url_get_file_handle = udp_get_file_handle,
    .priv_data_size      = sizeof(UDPContext),
    .priv_data_class     = &udp_class,
    .flags               = URL_PROTOCOL_FLAG_NETWORK,
};

ffio_fdopen 函数

ffio_fdopen函数定义如下:

ffio_fdopen
1
2
3
4
5
6
7
8
9
10
11
int ffio_fdopen(AVIOContext **s, URLContext *h)
{
    uint8_t *buffer;
    ……
    buffer = av_malloc(buffer_size);

    *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, h,
                            (int (*)(void *, uint8_t *, int))ffurl_read,
                            (int (*)(void *, uint8_t *, int))ffurl_write,
                            (int64_t (*)(void *, uint64_t, int))ffurl_ffurl_seek).
}

ffio_fdopen会调用avio_alloc_context初始化一个AVIOContext, avio_alloc_context函数成功执行后会返回一个创建好的AVIOContext