parent
							
								
									8fe1597466
								
							
						
					
					
						commit
						5e37f0ad2b
					
				| @ -0,0 +1,295 @@ | ||||
| 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); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
					Loading…
					
					
				
		Reference in new issue