以读取flv文件为例,查看avio_read()函数的执行流程。
在av_probe_input_buffer2()函数会调用avio_read()
函数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 || s->write_flag) {
if((s->direct || size > s->buffer_size) && !s->update_checksum) {
// bypass the buffer and read data directly into buf
if(s->read_packet)
len = s->read_packet(s->opaque, buf, size);
if (len <= 0) {
/* do not modify buffer if EOF reached so that a seek back can
be done without rereading data */
s->eof_reached = 1;
if(len<0)
s->error= len;
break;
} else {
s->pos += len;
s->bytes_read += len;
size -= len;
buf += len;
// reset the buffer
s->buf_ptr = s->buffer;
s->buf_end = s->buffer/* + len*/;
}
} else {
fill_buffer(s);
len = s->buf_end - s->buf_ptr;
if (len == 0)
break;
}
} else {
memcpy(buf, s->buf_ptr, len);
buf += len;
s->buf_ptr += len;
size -= len;
}
}
if (size1 == size) {
if (s->error) return s->error;
if (avio_feof(s)) return AVERROR_EOF;
}
return size1 - size;
}
开始size为2048,s->buf_end和s->buf_ptr相等,而且s->direct为0,s->buffer_size为32768,所以执行fill_buffer()
函数fill_buffer()
static void fill_buffer(AVIOContext *s)
{
int max_buffer_size = s->max_packet_size ?
s->max_packet_size : IO_BUFFER_SIZE;
uint8_t *dst = s->buf_end - s->buffer + max_buffer_size < s->buffer_size ?
s->buf_end : s->buffer;
int len = s->buffer_size - (dst - s->buffer);
/* can't fill the buffer without read_packet, just set EOF if appropriate */
if (!s->read_packet && s->buf_ptr >= s->buf_end)
s->eof_reached = 1;
/* no need to do anything if EOF already reached */
if (s->eof_reached)
return;
if (s->update_checksum && dst == s->buffer) {
if (s->buf_end > s->checksum_ptr)
s->checksum = s->update_checksum(s->checksum, s->checksum_ptr,
s->buf_end - s->checksum_ptr);
s->checksum_ptr = s->buffer;
}
/* make buffer smaller in case it ended up large after probing */
if (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size) {
if (dst == s->buffer) {
int ret = ffio_set_buf_size(s, s->orig_buffer_size);
if (ret < 0)
av_log(s, AV_LOG_WARNING, "Failed to decrease buffer size\n");
s->checksum_ptr = dst = s->buffer;
}
av_assert0(len >= s->orig_buffer_size);
len = s->orig_buffer_size;
}
if (s->read_packet)
len = s->read_packet(s->opaque, dst, len);
else
len = 0;
if (len <= 0) {
/* do not modify buffer if EOF reached so that a seek back can
be done without rereading data */
s->eof_reached = 1;
if (len < 0)
s->error = len;
} else {
s->pos += len;
s->buf_ptr = dst;
s->buf_end = dst + len;
s->bytes_read += len;
}
}
其中max_buffer_size为32768.
刚进入函数fill_buffer()时s内容:
(gdb) p *s
$1 = {av_class = 0x1884b80, buffer = 0x2768740 "", buffer_size = 32768, buf_ptr = 0x2768740 "", buf_end = 0x2768740 "", opaque = 0x2768620, read_packet = 0x5f5190 <io_read_packet>, write_packet = 0x5f5180 <io_write_packet>,
seek = 0x5f5170 <io_seek>, pos = 0, must_flush = 0, eof_reached = 0, write_flag = 0, max_packet_size = 0, checksum = 0, checksum_ptr = 0x0, update_checksum = 0, error = 0, read_pause = 0x5f4670 <io_read_pause>,
read_seek = 0x5f4690 <io_read_seek>, seekable = 1, maxsize = 0, direct = 0, bytes_read = 0, seek_count = 0, writeout_count = 0, orig_buffer_size = 32768, short_seek_threshold = 4096, protocol_whitelist = 0x2768380 "file,crypto",
protocol_blacklist = 0x0, write_data_type = 0, ignore_boundary_point = 0, current_type = AVIO_DATA_MARKER_UNKNOWN, last_time = -9223372036854775808}
其中s->read_packet()回调函数io_read_packet()
函数io_read_packet()
int ffurl_read(URLContext *h, unsigned char *buf, int size)
{
if (!(h->flags & AVIO_FLAG_READ))
return AVERROR(EIO);
return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);
}
static int io_read_packet(void *opaque, uint8_t *buf, int buf_size)
{
AVIOInternal *internal = opaque;
return ffurl_read(internal->h, buf, buf_size);
}
其中h->prot内容如下:
(gdb) p *(h->prot)
$3 = {name = 0x189f6fe "file", url_open = 0x728790 <file_open>, url_open2 = 0, url_accept = 0, url_handshake = 0, url_read = 0x728740 <file_read>, url_write = 0x728710 <file_write>, url_seek = 0x728690 <file_seek>,
url_close = 0x728680 <file_close>, url_read_pause = 0, url_read_seek = 0, url_get_file_handle = 0x728190 <file_get_handle>, url_get_multi_file_handle = 0, url_shutdown = 0, priv_data_size = 32, priv_data_class = 0x18c5160, flags = 0,
url_check = 0x7285c0 <file_check>, url_open_dir = 0x728590 <file_open_dir>, url_read_dir = 0x728320 <file_read_dir>, url_close_dir = 0x728300 <file_close_dir>, url_delete = 0x728290 <file_delete>, url_move = 0x728230 <file_move>,
default_whitelist = 0x18c4fc0 "file,crypto"}
即url_read() 回调函数file_read()。
函数retry_transfer_wrapper()
static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
int size, int size_min,
int (*transfer_func)(URLContext *h,
uint8_t *buf,
int size))
{
int ret, len;
int fast_retries = 5;
int64_t wait_since = 0;
len = 0;
while (len < size_min) {
if (ff_check_interrupt(&h->interrupt_callback))
return AVERROR_EXIT;
ret = transfer_func(h, buf + len, size - len);
if (ret == AVERROR(EINTR))
continue;
if (h->flags & AVIO_FLAG_NONBLOCK)
return ret;
if (ret == AVERROR(EAGAIN)) {
ret = 0;
if (fast_retries) {
fast_retries--;
} else {
if (h->rw_timeout) {
if (!wait_since)
wait_since = av_gettime_relative();
else if (av_gettime_relative() > wait_since + h->rw_timeout)
return AVERROR(EIO);
}
av_usleep(1000);
}
} else if (ret < 1)
return (ret < 0 && ret != AVERROR_EOF) ? ret : len;
if (ret) {
fast_retries = FFMAX(fast_retries, 2);
wait_since = 0;
}
len += ret;
}
return len;
}
其中h->interrupt_callback内容
$6 = {callback = 0x4861d0 <decode_interrupt_cb>, opaque = 0x0}
函数transfer_func()回调函数file_read()
函数file_read()
static int file_read(URLContext *h, unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
int ret;
size = FFMIN(size, c->blocksize);
ret = read(c->fd, buf, size);
if (ret == 0 && c->follow)
return AVERROR(EAGAIN);
return (ret == -1) ? AVERROR(errno) : ret;
}
从文件读取数据后,在函数fill_buffer()末尾打印s
(gdb) p *s
$10 = {av_class = 0x1884b80, buffer = 0x2768740 "FLV\001\005", buffer_size = 32768, buf_ptr = 0x2768740 "FLV\001\005", buf_end = 0x2770740 "", opaque = 0x2768620, read_packet = 0x5f5190 <io_read_packet>,
write_packet = 0x5f5180 <io_write_packet>, seek = 0x5f5170 <io_seek>, pos = 32768, must_flush = 0, eof_reached = 0, write_flag = 0, max_packet_size = 0, checksum = 0, checksum_ptr = 0x0, update_checksum = 0, error = 0,
read_pause = 0x5f4670 <io_read_pause>, read_seek = 0x5f4690 <io_read_seek>, seekable = 1, maxsize = 0, direct = 0, bytes_read = 32768, seek_count = 0, writeout_count = 0, orig_buffer_size = 32768, short_seek_threshold = 4096,
protocol_whitelist = 0x2768380 "file,crypto", protocol_blacklist = 0x0, write_data_type = 0, ignore_boundary_point = 0, current_type = AVIO_DATA_MARKER_UNKNOWN, last_time = -9223372036854775808}