• FFmpeg 结构体学习(七): AVIOContext 分析


    在上文FFmpeg 结构体学习(六): AVCodecContext 分析我们学习了AVCodec结构体的相关内容。本文,我们将讲述一下AVIOContext。

    AVIOContext是FFMPEG管理输入输出数据的结构体。下面我们来分析一下该结构体里重要变量的含义和作用。

    一、源码整理

    首先我们先看一下结构体AVIOContext的定义的结构体源码(位于libavformat/avio.h):

     /**
     * Bytestream IO Context.
     * New fields can be added to the end with minor version bumps.
     * Removal, reordering and changes to existing fields require a major
     * version bump.
     * sizeof(AVIOContext) must not be used outside libav*.
     *
     * @note None of the function pointers in AVIOContext should be called
     *       directly, they should only be set by the client application
     *       when implementing custom I/O. Normally these are set to the
     *       function pointers specified in avio_alloc_context()
     */
    typedef struct {
        /**
         * A class for private options.
         *
         * If this AVIOContext is created by avio_open2(), av_class is set and
         * passes the options down to protocols.
         *
         * If this AVIOContext is manually allocated, then av_class may be set by
         * the caller.
         *
         * warning -- this field can be NULL, be sure to not pass this AVIOContext
         * to any av_opt_* functions in that case.
         */
        AVClass *av_class;
        unsigned char *buffer;  /**< Start of the buffer. */
        int buffer_size;        /**< Maximum buffer size */
        unsigned char *buf_ptr; /**< Current position in the buffer */
        unsigned char *buf_end; /**< End of the data, may be less than
                                     buffer+buffer_size if the read function returned
                                     less data than requested, e.g. for streams where
                                     no more data has been received yet. */
        void *opaque;           /**< A private pointer, passed to the read/write/seek/...
                                     functions. */
        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;            /**< position in the file of the current buffer */
        int must_flush;         /**< true if the next seek should flush */
        int eof_reached;        /**< true if eof reached */
        int write_flag;         /**< true if open for writing */
        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;              /**< contains the error code or 0 if no error happened */
        /**
         * Pause or resume playback for network streaming protocols - e.g. MMS.
         */
        int (*read_pause)(void *opaque, int pause);
        /**
         * Seek to a given timestamp in stream with the specified stream_index.
         * Needed for some network streaming protocols which don't support seeking
         * to byte position.
         */
        int64_t (*read_seek)(void *opaque, int stream_index,
                             int64_t timestamp, int flags);
        /**
         * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
         */
        int seekable;
     
        /**
         * max filesize, used to limit allocations
         * This field is internal to libavformat and access from outside is not allowed.
         */
         int64_t maxsize;
    } AVIOContext;

    二、AVIOContext 重点字段

    AVIOContext中有以下几个变量比较重要:

    unsigned char *buffer:缓存开始位置
    
    int buffer_size:缓存大小(默认32768)
    
    unsigned char *buf_ptr:当前指针读取到的位置
    
    unsigned char *buf_end:缓存结束的位置
    
    void *opaque:URLContext结构体

    在解码的情况下,buffer用于存储ffmpeg读入的数据。例如打开一个视频文件的时候,先把数据从硬盘读入buffer,然后在送给解码器用于解码。

    其中opaque指向了URLContext。注意,这个结构体并不在FFMPEG提供的头文件中,而是在FFMPEG的源代码中。从FFMPEG源代码中翻出的定义如下所示:

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

    URLContext结构体中还有一个结构体URLProtocol。注:每种协议(rtp,rtmp,file等)对应一个URLProtocol。这个结构体也不在FFMPEG提供的头文件中。从FFMPEG源代码中翻出其的定义:

    typedef struct URLProtocol {
        const char *name;
        int (*url_open)(URLContext *h, const char *url, int flags);
        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 priv_data_size;
        const AVClass *priv_data_class;
        int flags;
        int (*url_check)(URLContext *h, int mask);
    } URLProtocol;
    在这个结构体中,除了一些回调函数接口之外,有一个变量const char *name,该变量存储了协议的名称。每一种输入协议都对应这样一个结构体。
    比如说,文件协议中代码如下(file.c):
    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,
    };

    libRTMP中代码如下(libRTMP.c):

    URLProtocol ff_rtmp_protocol = {
        .name                = "rtmp",
        .url_open            = rtmp_open,
        .url_read            = rtmp_read,
        .url_write           = rtmp_write,
        .url_close           = rtmp_close,
        .url_read_pause      = rtmp_read_pause,
        .url_read_seek       = rtmp_read_seek,
        .url_get_file_handle = rtmp_get_file_handle,
        .priv_data_size      = sizeof(RTMP),
        .flags               = URL_PROTOCOL_FLAG_NETWORK,
    };

    udp协议代码如下(udp.c):

    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),
        .flags               = URL_PROTOCOL_FLAG_NETWORK,
    };

    等号右边的函数是完成具体读写功能的函数。可以看一下file协议的几个函数(其实就是读文件,写文件这样的操作)(file.c):

    /* standard file protocol */
     
    static int file_read(URLContext *h, unsigned char *buf, int size)
    {
        int fd = (intptr_t) h->priv_data;
        int r = read(fd, buf, size);
        return (-1 == r)?AVERROR(errno):r;
    }
     
    static int file_write(URLContext *h, const unsigned char *buf, int size)
    {
        int fd = (intptr_t) h->priv_data;
        int r = write(fd, buf, size);
        return (-1 == r)?AVERROR(errno):r;
    }
     
    static int file_get_handle(URLContext *h)
    {
        return (intptr_t) h->priv_data;
    }
     
    static int file_check(URLContext *h, int mask)
    {
        struct stat st;
        int ret = stat(h->filename, &st);
        if (ret < 0)
            return AVERROR(errno);
     
        ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ  : 0;
        ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
     
        return ret;
    }
     
    #if CONFIG_FILE_PROTOCOL
     
    static int file_open(URLContext *h, const char *filename, int flags)
    {
        int access;
        int fd;
     
        av_strstart(filename, "file:", &filename);
     
        if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
            access = O_CREAT | O_TRUNC | O_RDWR;
        } else if (flags & AVIO_FLAG_WRITE) {
            access = O_CREAT | O_TRUNC | O_WRONLY;
        } else {
            access = O_RDONLY;
        }
    #ifdef O_BINARY
        access |= O_BINARY;
    #endif
        fd = open(filename, access, 0666);
        if (fd == -1)
            return AVERROR(errno);
        h->priv_data = (void *) (intptr_t) fd;
        return 0;
    }
     
    /* XXX: use llseek */
    static int64_t file_seek(URLContext *h, int64_t pos, int whence)
    {
        int fd = (intptr_t) h->priv_data;
        if (whence == AVSEEK_SIZE) {
            struct stat st;
            int ret = fstat(fd, &st);
            return ret < 0 ? AVERROR(errno) : st.st_size;
        }
        return lseek(fd, pos, whence);
    }
     
    static int file_close(URLContext *h)
    {
        int fd = (intptr_t) h->priv_data;
        return close(fd);
    }
  • 相关阅读:
    Product of Array Except Self
    Sliding Window Maximum
    First Bad Version
    Perfect Squares
    IPsec Note
    BGP实验第9-10选路原则
    BGP选路第3条原则
    BGP选路原则第1条至第8条
    BGP选路原则笔记 Cyrus
    Lab Block hole of BGP
  • 原文地址:https://www.cnblogs.com/renhui/p/9494887.html
Copyright © 2020-2023  润新知