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