diff --git a/libavformat/avio_internal.h b/libavformat/avio_internal.h index c575df803527a..fe87f2a288745 100644 --- a/libavformat/avio_internal.h +++ b/libavformat/avio_internal.h @@ -100,7 +100,9 @@ int ffio_realloc_buf(AVIOContext *s, int buf_size); * * Will ensure that when reading sequentially up to buf_size, seeking * within the current pos and pos+buf_size is possible. - * Once the stream position moves outside this window this guarantee is lost. + * Once the stream position moves outside this window or another + * ffio_ensure_seekback call requests a buffer outside this window this + * guarantee is lost. */ int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size); diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index a48ceebaefe66..050c06399845b 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -528,7 +528,7 @@ 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 ? + 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); @@ -707,13 +707,6 @@ int avio_read_partial(AVIOContext *s, unsigned char *buf, int size) len = s->buf_end - s->buf_ptr; if (len == 0) { - /* Reset the buf_end pointer to the start of the buffer, to make sure - * the fill_buffer call tries to read as much data as fits into the - * full buffer, instead of just what space is left after buf_end. - * This avoids returning partial packets at the end of the buffer, - * for packet based inputs. - */ - s->buf_end = s->buf_ptr = s->buffer; fill_buffer(s); len = s->buf_end - s->buf_ptr; } @@ -926,6 +919,11 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) } else { buffer_size = IO_BUFFER_SIZE; } + if (!(h->flags & AVIO_FLAG_WRITE) && h->is_streamed) { + if (buffer_size > INT_MAX/2) + return AVERROR(EINVAL); + buffer_size *= 2; + } buffer = av_malloc(buffer_size); if (!buffer) return AVERROR(ENOMEM); @@ -979,32 +977,46 @@ URLContext* ffio_geturlcontext(AVIOContext *s) return NULL; } +static void update_checksum(AVIOContext *s) +{ + if (s->update_checksum && s->buf_ptr > s->checksum_ptr) { + s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, + s->buf_ptr - s->checksum_ptr); + } +} + int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size) { uint8_t *buffer; int max_buffer_size = s->max_packet_size ? s->max_packet_size : IO_BUFFER_SIZE; - int filled = s->buf_end - s->buffer; - ptrdiff_t checksum_ptr_offset = s->checksum_ptr ? s->checksum_ptr - s->buffer : -1; + ptrdiff_t filled = s->buf_end - s->buf_ptr; + + if (buf_size <= s->buf_end - s->buf_ptr) + return 0; - buf_size += s->buf_ptr - s->buffer + max_buffer_size; + buf_size += max_buffer_size - 1; - if (buf_size < filled || s->seekable || !s->read_packet) + if (buf_size + s->buf_ptr - s->buffer <= s->buffer_size || s->seekable || !s->read_packet) return 0; av_assert0(!s->write_flag); - buffer = av_malloc(buf_size); - if (!buffer) - return AVERROR(ENOMEM); - - memcpy(buffer, s->buffer, filled); - av_free(s->buffer); - s->buf_ptr = buffer + (s->buf_ptr - s->buffer); - s->buf_end = buffer + (s->buf_end - s->buffer); - s->buffer = buffer; - s->buffer_size = buf_size; - if (checksum_ptr_offset >= 0) - s->checksum_ptr = s->buffer + checksum_ptr_offset; + if (buf_size <= s->buffer_size) { + update_checksum(s); + memmove(s->buffer, s->buf_ptr, filled); + } else { + buffer = av_malloc(buf_size); + if (!buffer) + return AVERROR(ENOMEM); + update_checksum(s); + memcpy(buffer, s->buf_ptr, filled); + av_free(s->buffer); + s->buffer = buffer; + s->buffer_size = buf_size; + } + s->buf_ptr = s->buffer; + s->buf_end = s->buffer + filled; + s->checksum_ptr = s->buffer; return 0; }