FFMPEG 版本3.2 release。
函数fill_buffer(AVIOContext *s)
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; }}
函数fill_buffer()的作用
从file或者网络流等读数据到AVIOContext *s的buf。
如果先调用函数ffio_fdopen(),再调用函数fill_buffer()为例,并且假设read_packet()指向函数io_read_packet(),则执行过程如下:
执行函数s->read_packet(s->opaque, dst, len)
该函数的作用为通过指针s->opaque指向的结构体中的变量,获取数据流并复制到dst。
例如:read_packet()指向函数io_read_packet().
函数io_read_packet()位于libavformat/aviobuf.c。
函数ffurl_read()位于libavformat/avio.c
函数retry_transfer_wrapper()位于libavformat/avio.c
如果输入的是文件,例如test.flv,则函数transfer_func(h, buf + len, size - len)指向file_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);}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 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;}
输入文件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;}
输入是rtmp协议流transfer_func()回调函数rtmp_read()
libavformat/rtmpproto.c
static int rtmp_read(URLContext *s, uint8_t *buf, int size){ RTMPContext *rt = s->priv_data; int orig_size = size; int ret; while (size > 0) { int data_left = rt->flv_size - rt->flv_off; if (data_left >= size) { memcpy(buf, rt->flv_data + rt->flv_off, size); rt->flv_off += size; return orig_size; } if (data_left > 0) { memcpy(buf, rt->flv_data + rt->flv_off, data_left); buf += data_left; size -= data_left; rt->flv_off = rt->flv_size; return data_left; } if ((ret = get_packet(s, 0)) < 0) return ret; } return orig_size;}
更新AVIOContext *s有关buf的指针
从数据流中获取数据后,更新AVIOContext *s中的指针,如 s->pos,s->buf_ptr,s->buf_end = dst,s->bytes_read 。