ffmpeg的IO操作

ffmpeg的IO操作主要在libavformat库中实现,部分实现用到了libavutl中的工具。网上有一些介绍ffmpeg的IO的文章,但是有些比较老了,并且一些现在ffmpeg结构已经一些变化,比如ByteIOContext已经改名为AVIOContext,本文章主要介绍IO基础,以及一些ffmpeg对于一些内存操作的方法。

所谓IO就是数据的存取,主要的途径也就是文件或者网络。数据IO是基于文件格式的,与具体的编码标准无关。


ffmpeg对各种协议实现了封装,使用同样的接口,完成对不同数据的读取。比较屌。

ffmpeg所有的协议的注册是在av_register_all中完成的。协议保存在链表first_protocol中。

ffmpeg的IO层次,不同的封装层次:

ffmpeg的IO操作_第1张图片

URLContext层次的操作主要有:url_open,url_read,url_write,url_seek,url_close等

AVIOContext层次的操作主要有:avio_open,avio_clse,avio_rxxx,avio_wxxx。事实上这是对URLContext层次的上层操作。或者更高层次的抽象封装。

avio_rxxx和avio_wxxx简介的调用ffurl_read,ffurl_write,实现读写操作,而avio_open根据文件名来实现avio_rxxx和avio_wxxx和不用媒介的操作函数ffurl_read,ffurl_write的绑定

avio_rxxx和avio_wxxx实现的是对内存缓冲区中数据的操作,当缓冲区中数据不足或者缓冲区将要溢出时,调用flush_buffer和fill_buffer将数据把数据读到媒介中。

实现IO的重要的结构:

ffmpeg的针对不同的媒介的数据操作方法称为url_xxx并记录在URLProtocol中

URLProtocol:用于各种数据传输协议,结构中定义了一系列的接口(回调函数),包括协议的打开,读,写,定位等。

typedef struct URLProtocol {
    const char *name;//协议名称
    int     (*url_open)( URLContext *h, const char *url, int flags);//打开协议的函数
    int     (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);//
    int     (*url_read)( URLContext *h, unsigned char *buf, int size);//读
    int     (*url_write)(URLContext *h, const unsigned char *buf, int size);//
    int64_t (*url_seek)( URLContext *h, int64_t pos, int whence);
    int     (*url_close)(URLContext *h);
    struct URLProtocol *next;
    int (*url_read_pause)(URLContext *h, int pause);
    int64_t (*url_read_seek)(URLContext *h, int stream_index, int64_t timestamp, int flags);
    int (*url_get_file_handle)(URLContext *h);
    int (*url_get_multi_file_handle)(URLContext *h, int **handles, int *numhandles);
    int (*url_shutdown)(URLContext *h, int flags);
    int priv_data_size;
    const AVClass *priv_data_class;
    int flags;
    int (*url_check)(URLContext *h, int mask);
} URLProtocol;
URLContext 协议的上下文:可以看成某种协议的载体,在打开一个协议的时候,全局函数url_open会根据文件的前缀来判断使用的协议,并为该协议分配好资源,在调用url_connect来打开具体的协议,即调用prot->url_open

typedef struct URLContext {
    const AVClass *av_class;    /**< information for av_log(). Set by url_open(). */
    struct URLProtocol *prot;
    void *priv_data;
    char *filename;             /**< specified URL */
    int flags;
    int max_packet_size;        /**< if non zero, the stream is packetized with this max packet size */
    int is_streamed;            /**< true if streamed (no seek possible), default = false */
    int is_connected;
    AVIOInterruptCB interrupt_callback;
    int64_t rw_timeout;         /**< maximum time to wait for (network) read/write operation completion, in mcs */
} URLContext;

比如file协议:

URLProtocol ff_file_protocol = {
    .name                = "file",
    .url_open            = file_open,
    .url_read            = file_read,
    .url_write           = file_write,
    .url_seek            = file_seek,
    .url_close           = file_close,
    .url_get_file_handle = file_get_handle,
    .url_check           = file_check,
    .priv_data_size      = sizeof(FileContext),
    .priv_data_class     = &file_class,
};

AVIOContext:

typedef struct AVIOContext {
    const AVClass *av_class;
    unsigned char *buffer;  
    int buffer_size;        
    unsigned char *buf_ptr; 
    unsigned char *buf_end;
    void *opaque;         
    int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
    int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
    int64_t (*seek)(void *opaque, int64_t offset, int whence);
    int64_t pos;         
    int must_flush;         
    int eof_reached;    
    int write_flag;        
    int max_packet_size;
    unsigned long checksum;
    unsigned char *checksum_ptr;
    unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
    int error;            
    int (*read_pause)(void *opaque, int pause);
    int64_t (*read_seek)(void *opaque, int stream_index, int64_t timestamp, int flags);
    int seekable;
    int64_t maxsize;
    int direct;
    int64_t bytes_read;
    int seek_count;
    int writeout_count;
    int orig_buffer_size;
} AVIOContext;
AVIOContext和URLContext的关系:

我们知道数据源头肯定是URLProtocol,而URLContext是对URLProtocol的封装,所以AVIOContext肯定和URLContext有某种关系。在url_fopen中,调用了url_fdopen对AVIOContext进行初始化。将read_packet,write_packet,seek_packet分别设置为ffurl_read, ffurl_write,ffurl_seek。

 *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, h,
                            (void*)ffurl_read, (void*)ffurl_write, (void*)ffurl_seek);


avio_open/avio_open2函数的作用

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);//通过解析文件名,找到对应的操作集URLProtocol
    if (err < 0)
        return err;
    /*
     *调用ffio_init_context把URLProtocol中的ffurl_read, ffurl_write, ffurl_seek,注册到AVIOContext结构体中,成为read_packet, write_packet的回调函数
    */
    err = ffio_fdopen(s, h);
    if (err < 0) {
        ffurl_close(h);
        return err;
    }
    return 0;
}

解析文件名,找到对应的操作集URLProtocol
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;
}



未完待续。。。。








你可能感兴趣的:(内存,源代码,ffmpeg)