FFmpeg 協議初步學習

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;


1、context 當前運行的上下文環境,其實說白了就是C的全局變量,用來保存當前模塊運行時的多個函數需要使用到的共同變量。每一個模塊裏面都會有一個 context 來表示運行上下文,模塊裏面的具體實現都要使用到和其對應的 context 。file 協議是在 file.c 中實現的,裏面有一個 FileContext, 和一個 AVClass file_class

2、URLContext  中的 av_class 是它自身的 AVClass ffurl_context_class

3、URLContext 中的 prot 是指向具體的協議的,URLProtocol 抽象出了一些接口,上層使用這些接口去操作數據,而在不同的協議裏面實現了這些接口。打開的是一個文件協議的話,此時的 prot 就是指向 URLProtocol ff_file_protocol 


4、URLContext  中的 priv_data,有點比較難理解,先理解一下 URLProtocol  再回來就比較容易理解一點

typedef struct URLProtocol {
    const char *name;
    int     (*url_open)( URLContext *h, const char *url, int flags);
    /**
     * This callback is to be used by protocols which open further nested
     * protocols. options are then to be passed to ffurl_open()/ffurl_connect()
     * for those nested protocols.
     */
    int     (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);

    /**
     * Read data from the protocol.
     * If data is immediately available (even less than size), EOF is
     * reached or an error occurs (including EINTR), return immediately.
     * Otherwise:
     * In non-blocking mode, return AVERROR(EAGAIN) immediately.
     * In blocking mode, wait for data/EOF/error with a short timeout (0.1s),
     * and return AVERROR(EAGAIN) on timeout.
     * Checking interrupt_callback, looping on EINTR and EAGAIN and until
     * enough data has been read is left to the calling function; see
     * retry_transfer_wrapper in avio.c.
     */
    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;



5、URLProtocol  中的 priv_data_size 指的是當前具體實現的 context 的大小,在file協議中就是 FileContext 結構的大小

6、URLProtocol 中的 priv_data_class 指的是當前具體實現的 AVClass,在file協議中就是指向 AVClass file_class

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,
};



7、file 協議的具體實現,實現了 URLProtocol  中的接口,並且裏面的兩個 priv 變量是指的是它自身的 FileContext 結構的大小和 AVClass file_class

8、URLContext  中的 priv_data 指向的其實是具體協議的 context,在file協議中就是分配的一個 FileContext,FileContext 中的 class 指向的自身的 AVClass ,也就是和 ff_file_protocol  中的 priv_data_class 指向的是同一個AVClass

typedef struct FileContext {
    const AVClass *class;
    int fd;
    int trunc;
    int blocksize;
} FileContext;



9、AVClass 目前還沒有發現是幹嘛用的,在file協議中好像是和一些設置參數有關,通過參數可以更改 FileContext 中成員的值

static const AVClass file_class = {
    .class_name = "file",
    .item_name  = av_default_item_name,
    .option     = file_options,
    .version    = LIBAVUTIL_VERSION_INT,
};



10、找到具體的協議是在 url_find_protocol 函數中查找的,查找是按照協議的名字和 URLProtocol.name 匹配的,如果給到的 filename 是沒有寫協議的路徑,會被直接當做 file 協議。查找到了相關的協議後就要分配 context(比如:FileContext),並設置 URLContext  中的成員,實現是在 url_alloc_for_protocol 函數中

11、avio.c 中維護了一個 URLProtocol 列表,通過 ffurl_register_protocol 函數將協議註冊。這個函數是在 av_register_all 裏面觸發的,在這裏會完成所有的 codecs,muxers,protocol,libraries 等的註冊


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章