FFMPEG 版本3.2 release。網絡
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; } }
從file或者網絡流等讀數據到AVIOContext *s的buf。app
若是先調用函數ffio_fdopen(),再調用函數fill_buffer()爲例,而且假設read_packet()指向函數io_read_packet(),則執行過程以下:函數
該函數的做用爲經過指針s->opaque指向的結構體中的變量,獲取數據流並複製到dst。ui
例如:read_packet()指向函數io_read_packet().url
函數io_read_packet()位於libavformat/aviobuf.c。spa
函數ffurl_read()位於libavformat/avio.c指針
函數retry_transfer_wrapper()位於libavformat/avio.ccode
若是輸入的是文件,例如test.flv,則函數transfer_func(h, buf + len, size - len)指向file_read()。orm
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; }
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; }
libavformat/rtmpproto.cget
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中的指針,如 s->pos,s->buf_ptr,s->buf_end = dst,s->bytes_read 。