以讀取flv文件爲例,查看avio_read()函數的執行流程。app
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()函數
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.ui
剛進入函數fill_buffer()時s內容:url
(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()spa
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內容以下:code
(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()。get
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}input
函數transfer_func()回調函數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()末尾打印sit
(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}