1 AVIOContext
URLContext它是一个不带缓冲的IO 结构体,读取实际是调用底层的IO 接口, 只仅仅统一不同文件IO API 而已。 AVIOContext 是一个在URLContext 基础上,带缓冲的结构体, 这样做的好处是加快IO 效率, 减少IO 次数。假设网络数据,只仅仅读取一个字节,也要发起一次网络请求的话难免会降低效率。 假设先预先申请一块buff ,当请求的数据,小于buff 缓存的数据,那么直接在buff 中memcpy 就好了, 这样会极大的提高处理性能。下面我们将介绍它是如何实现缓冲功能的。
2 avio_open()
avio_open(AVIOContext **s, const char *filename, int flags) ,它初始化AVIOContext 一些变量, open 底层文件,申请缓冲buff 的大小。当我们调用avio_open()函数时,它将call 到ffio_fdopen() , 这函数完成缓冲buff 的申请。
int ffio_fdopen(AVIOContext **s, URLContext *h)
{
.........
max_packet_size = h->max_packet_size;
if (max_packet_size) {
buffer_size = max_packet_size; /* 如果底层IO 有指定size , 就alloc 底层指定的大小的buff */
} else {
buffer_size = IO_BUFFER_SIZE;//没有指定的话, alloc 默认size 32768
}
buffer = av_malloc(buffer_size); // alloc 缓冲buff
..........
}
3 avio_read()
如下图,乃是AVIOContext 自带的注解,
typedef struct AVIOContext {
…
unsigned char *buffer; /**buffer 的起始位置 /
int buffer_size; / alloc缓冲buffer 的size */
unsigned char buf_ptr; / 当前读到的位置 /
unsigned char buf_end; / 缓存数据的尾端/
int64_t pos; // 底层IO 函数 真正读取到的位置
…
}
下面我们在来分析下avio_read() 函数实现
int avio_read(AVIOContext *s, unsigned char *buf, int size)
{
int len, size1;
size1 = size;
while (size > 0) {
len = FFMIN(s->buf_end - s->buf_ptr, size);
if (len == 0 ) {
if((s->direct || size > s->buffer_size) && !s->update_checksum) {
len = read_packet_wrapper(s, buf, size);//len 值等于0, 请求read size 大于buff size 时,向底层发起IO 请求,一次性读完申请的size
} else {
fill_buffer(s);//len 值等于0,请求read size 小于buff size 时,将buff 读满
len = s->buf_end - s->buf_ptr;//修改此时的数据长度
if (len == 0)
break;
}
} else {
memcpy(buf, s->buf_ptr, len);//当size 不为0 时, 先从缓冲buff 里面读取数据
buf += len;
s->buf_ptr += len;
size -= len;
}
}
.........
return size1 - size;
}
4 avio_write()
这是带缓冲的写函数,实现也比较简单,当写到缓冲buff 的数据满了时,就flush buffer。 将数据通过底层IO 函数写到文件中。
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
{
..........
while (size > 0) {
int len = FFMIN(s->buf_end - s->buf_ptr, size);
memcpy(s->buf_ptr, buf, len); //先将数据写到缓冲buff
s->buf_ptr += len;
if (s->buf_ptr >= s->buf_end) //当缓冲buff 满了时, 通过底层IO 函数flush 到文件中去
flush_buffer(s);
buf += len;
size -= len;
}
}