X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Faviobuf.c;h=ddfa4ecbf1cc67aebebca055027a2ef4f0864574;hb=0bf3a7361d17d596a5044882098f56817db0e103;hp=5a33f82950c32b2a1dee172ce4c61ed97469c51e;hpb=d6b62ce1aced9e2456582870382f384581cc7cbb;p=ffmpeg diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 5a33f82950c..ddfa4ecbf1c 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -40,29 +40,26 @@ * data instead of calling the protocol seek function, for seekable * protocols. */ -#define SHORT_SEEK_THRESHOLD 4096 - -typedef struct AVIOInternal { - URLContext *h; -} AVIOInternal; +#define SHORT_SEEK_THRESHOLD 32768 static void *ff_avio_child_next(void *obj, void *prev) { AVIOContext *s = obj; - AVIOInternal *internal = s->opaque; - return prev ? NULL : internal->h; + return prev ? NULL : s->opaque; } -static const AVClass *ff_avio_child_class_next(const AVClass *prev) +static const AVClass *child_class_iterate(void **iter) { - return prev ? NULL : &ffurl_context_class; + const AVClass *c = *iter ? NULL : &ffurl_context_class; + *iter = (void*)(uintptr_t)c; + return c; } #define OFFSET(x) offsetof(AVIOContext,x) #define E AV_OPT_FLAG_ENCODING_PARAM #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption ff_avio_options[] = { - {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, + {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D }, { NULL }, }; @@ -72,7 +69,7 @@ const AVClass ff_avio_class = { .version = LIBAVUTIL_VERSION_INT, .option = ff_avio_options, .child_next = ff_avio_child_next, - .child_class_next = ff_avio_child_class_next, + .child_class_iterate = child_class_iterate, }; static void fill_buffer(AVIOContext *s); @@ -255,6 +252,9 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) if(!s) return AVERROR(EINVAL); + if ((whence & AVSEEK_SIZE)) + return s->seek ? s->seek(s->opaque, offset, AVSEEK_SIZE) : AVERROR(ENOSYS); + buffer_size = s->buf_end - s->buffer; // pos is the absolute position that the beginning of s->buffer corresponds to in the file pos = s->pos - (s->write_flag ? 0 : buffer_size); @@ -273,13 +273,9 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) if (offset < 0) return AVERROR(EINVAL); - if (s->short_seek_get) { - short_seek = s->short_seek_get(s->opaque); - /* fallback to default short seek */ - if (short_seek <= 0) - short_seek = s->short_seek_threshold; - } else - short_seek = s->short_seek_threshold; + short_seek = s->short_seek_threshold; + if (s->short_seek_get) + short_seek = FFMAX(s->short_seek_get(s->opaque), short_seek); offset1 = offset - pos; // "offset1" is the relative offset from the beginning of s->buffer s->buf_ptr_max = FFMAX(s->buf_ptr_max, s->buf_ptr); @@ -434,26 +430,6 @@ PUT_STR16(be, 1) #undef PUT_STR16 -int ff_get_v_length(uint64_t val) -{ - int i = 1; - - while (val >>= 7) - i++; - - return i; -} - -void ff_put_v(AVIOContext *bc, uint64_t val) -{ - int i = ff_get_v_length(val); - - while (--i > 0) - avio_w8(bc, 128 | (uint8_t)(val >> (7*i))); - - avio_w8(bc, val & 127); -} - void avio_wl64(AVIOContext *s, uint64_t val) { avio_wl32(s, (uint32_t)(val & 0xffffffff)); @@ -533,14 +509,7 @@ static int read_packet_wrapper(AVIOContext *s, uint8_t *buf, int size) if (!s->read_packet) return AVERROR(EINVAL); ret = s->read_packet(s->opaque, buf, size); -#if FF_API_OLD_AVIO_EOF_0 - if (!ret && !s->max_packet_size) { - av_log(NULL, AV_LOG_WARNING, "Invalid return value 0 for stream protocol\n"); - ret = AVERROR_EOF; - } -#else av_assert2(ret || s->max_packet_size); -#endif return ret; } @@ -550,7 +519,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); @@ -570,7 +539,7 @@ static void fill_buffer(AVIOContext *s) } /* 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 (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size && len >= s->orig_buffer_size) { if (dst == s->buffer && s->buf_ptr != dst) { int ret = ffio_set_buf_size(s, s->orig_buffer_size); if (ret < 0) @@ -578,7 +547,6 @@ static void fill_buffer(AVIOContext *s) s->checksum_ptr = dst = s->buffer; } - av_assert0(len >= s->orig_buffer_size); len = s->orig_buffer_size; } @@ -697,9 +665,11 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size) int ffio_read_size(AVIOContext *s, unsigned char *buf, int size) { int ret = avio_read(s, buf, size); - if (ret != size) - return AVERROR_INVALIDDATA; - return ret; + if (ret == size) + return ret; + if (ret < 0 && ret != AVERROR_EOF) + return ret; + return AVERROR_INVALIDDATA; } int ffio_read_indirect(AVIOContext *s, unsigned char *buf, int size, const unsigned char **data) @@ -719,7 +689,7 @@ int avio_read_partial(AVIOContext *s, unsigned char *buf, int size) int len; if (size < 0) - return -1; + return AVERROR(EINVAL); if (s->read_packet && s->write_flag) { len = read_packet_wrapper(s, buf, size); @@ -730,13 +700,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; } @@ -938,49 +901,8 @@ uint64_t ffio_read_varlen(AVIOContext *bc){ return val; } -static int io_read_packet(void *opaque, uint8_t *buf, int buf_size) -{ - AVIOInternal *internal = opaque; - return ffurl_read(internal->h, buf, buf_size); -} - -static int io_write_packet(void *opaque, uint8_t *buf, int buf_size) -{ - AVIOInternal *internal = opaque; - return ffurl_write(internal->h, buf, buf_size); -} - -static int64_t io_seek(void *opaque, int64_t offset, int whence) -{ - AVIOInternal *internal = opaque; - return ffurl_seek(internal->h, offset, whence); -} - -static int io_short_seek(void *opaque) -{ - AVIOInternal *internal = opaque; - return ffurl_get_short_seek(internal->h); -} - -static int io_read_pause(void *opaque, int pause) -{ - AVIOInternal *internal = opaque; - if (!internal->h->prot->url_read_pause) - return AVERROR(ENOSYS); - return internal->h->prot->url_read_pause(internal->h, pause); -} - -static int64_t io_read_seek(void *opaque, int stream_index, int64_t timestamp, int flags) -{ - AVIOInternal *internal = opaque; - if (!internal->h->prot->url_read_seek) - return AVERROR(ENOSYS); - return internal->h->prot->url_read_seek(internal->h, stream_index, timestamp, flags); -} - int ffio_fdopen(AVIOContext **s, URLContext *h) { - AVIOInternal *internal = NULL; uint8_t *buffer = NULL; int buffer_size, max_packet_size; @@ -990,18 +912,19 @@ 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); - internal = av_mallocz(sizeof(*internal)); - if (!internal) - goto fail; - - internal->h = h; - - *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, - internal, io_read_packet, io_write_packet, io_seek); + *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, h, + (int (*)(void *, uint8_t *, int)) ffurl_read, + (int (*)(void *, uint8_t *, int)) ffurl_write, + (int64_t (*)(void *, int64_t, int))ffurl_seek); if (!*s) goto fail; @@ -1021,76 +944,119 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) (*s)->max_packet_size = max_packet_size; (*s)->min_packet_size = h->min_packet_size; if(h->prot) { - (*s)->read_pause = io_read_pause; - (*s)->read_seek = io_read_seek; + (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause; + (*s)->read_seek = + (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek; if (h->prot->url_read_seek) (*s)->seekable |= AVIO_SEEKABLE_TIME; } - (*s)->short_seek_get = io_short_seek; + (*s)->short_seek_get = (int (*)(void *))ffurl_get_short_seek; (*s)->av_class = &ff_avio_class; return 0; fail: - av_freep(&internal); av_freep(&buffer); return AVERROR(ENOMEM); } URLContext* ffio_geturlcontext(AVIOContext *s) { - AVIOInternal *internal; if (!s) return NULL; - internal = s->opaque; - if (internal && s->read_packet == io_read_packet) - return internal->h; + if (s->opaque && s->read_packet == (int (*)(void *, uint8_t *, int))ffurl_read) + return s->opaque; else 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); + 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; +} + +int ffio_set_buf_size(AVIOContext *s, int buf_size) +{ + uint8_t *buffer; 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->orig_buffer_size = s->buffer_size = buf_size; - if (checksum_ptr_offset >= 0) - s->checksum_ptr = s->buffer + checksum_ptr_offset; + s->buf_ptr = s->buf_ptr_max = buffer; + url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); return 0; } -int ffio_set_buf_size(AVIOContext *s, int buf_size) +int ffio_realloc_buf(AVIOContext *s, int buf_size) { uint8_t *buffer; + int data_size; + + if (!s->buffer_size) + return ffio_set_buf_size(s, buf_size); + + if (buf_size <= s->buffer_size) + return 0; + buffer = av_malloc(buf_size); if (!buffer) return AVERROR(ENOMEM); + data_size = s->write_flag ? (s->buf_ptr - s->buffer) : (s->buf_end - s->buf_ptr); + if (data_size > 0) + memcpy(buffer, s->write_flag ? s->buffer : s->buf_ptr, data_size); av_free(s->buffer); s->buffer = buffer; - s->orig_buffer_size = + s->orig_buffer_size = buf_size; s->buffer_size = buf_size; - s->buf_ptr = s->buf_ptr_max = buffer; - url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); + s->buf_ptr = s->write_flag ? (s->buffer + data_size) : s->buffer; + if (s->write_flag) + s->buf_ptr_max = s->buffer + data_size; + + s->buf_end = s->write_flag ? (s->buffer + s->buffer_size) : (s->buf_ptr + data_size); + return 0; } @@ -1164,6 +1130,8 @@ int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags, URLContext *h; int err; + *s = NULL; + err = ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist, blacklist, NULL); if (err < 0) return err; @@ -1181,25 +1149,17 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, return ffio_open_whitelist(s, filename, flags, int_cb, options, NULL, NULL); } -int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, - const AVIOInterruptCB *int_cb, AVDictionary **options) -{ - return ffio_open_whitelist(pb, url, flags, int_cb, options, s->protocol_whitelist, s->protocol_blacklist); -} - int avio_close(AVIOContext *s) { - AVIOInternal *internal; URLContext *h; if (!s) return 0; avio_flush(s); - internal = s->opaque; - h = internal->h; + h = s->opaque; + s->opaque = NULL; - av_freep(&s->opaque); av_freep(&s->buffer); if (s->write_flag) av_log(s, AV_LOG_VERBOSE, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count); @@ -1222,14 +1182,26 @@ int avio_closep(AVIOContext **s) int avio_printf(AVIOContext *s, const char *fmt, ...) { va_list ap; - char buf[4096]; /* update doc entry in avio.h if changed */ - int ret; + AVBPrint bp; + av_bprint_init(&bp, 0, INT_MAX); va_start(ap, fmt); - ret = vsnprintf(buf, sizeof(buf), fmt, ap); + av_vbprintf(&bp, fmt, ap); va_end(ap); - avio_write(s, buf, strlen(buf)); - return ret; + if (!av_bprint_is_complete(&bp)) { + av_bprint_finalize(&bp, NULL); + s->error = AVERROR(ENOMEM); + return AVERROR(ENOMEM); + } + avio_write(s, bp.str, bp.len); + av_bprint_finalize(&bp, NULL); + return bp.len; +} + +void avio_print_string_array(AVIOContext *s, const char *strings[]) +{ + for(; *strings; strings++) + avio_write(s, (const unsigned char *)*strings, strlen(*strings)); } int avio_pause(AVIOContext *s, int pause) @@ -1279,8 +1251,7 @@ int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size) int avio_accept(AVIOContext *s, AVIOContext **c) { int ret; - AVIOInternal *internal = s->opaque; - URLContext *sc = internal->h; + URLContext *sc = s->opaque; URLContext *cc = NULL; ret = ffurl_accept(sc, &cc); if (ret < 0) @@ -1290,8 +1261,7 @@ int avio_accept(AVIOContext *s, AVIOContext **c) int avio_handshake(AVIOContext *c) { - AVIOInternal *internal = c->opaque; - URLContext *cc = internal->h; + URLContext *cc = c->opaque; return ffurl_handshake(cc); } @@ -1307,22 +1277,21 @@ typedef struct DynBuffer { static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size) { DynBuffer *d = opaque; - unsigned new_size, new_allocated_size; + unsigned new_size; /* reallocate buffer if needed */ - new_size = d->pos + buf_size; - new_allocated_size = d->allocated_size; - if (new_size < d->pos || new_size > INT_MAX/2) - return -1; - while (new_size > new_allocated_size) { - if (!new_allocated_size) - new_allocated_size = new_size; - else + new_size = (unsigned)d->pos + buf_size; + if (new_size < d->pos || new_size > INT_MAX) + return AVERROR(ERANGE); + if (new_size > d->allocated_size) { + unsigned new_allocated_size = d->allocated_size ? d->allocated_size + : new_size; + int err; + while (new_size > new_allocated_size) new_allocated_size += new_allocated_size / 2 + 1; - } - if (new_allocated_size > d->allocated_size) { - int err; + new_allocated_size = FFMIN(new_allocated_size, INT_MAX); + if ((err = av_reallocp(&d->buffer, new_allocated_size)) < 0) { d->allocated_size = 0; d->size = 0; @@ -1360,8 +1329,10 @@ static int64_t dyn_buf_seek(void *opaque, int64_t offset, int whence) offset += d->pos; else if (whence == SEEK_END) offset += d->size; - if (offset < 0 || offset > 0x7fffffffLL) - return -1; + if (offset < 0) + return AVERROR(EINVAL); + if (offset > INT_MAX) + return AVERROR(ERANGE); d->pos = offset; return 0; } @@ -1372,7 +1343,7 @@ static int url_open_dyn_buf_internal(AVIOContext **s, int max_packet_size) unsigned io_buffer_size = max_packet_size ? max_packet_size : 1024; if (sizeof(DynBuffer) + io_buffer_size < io_buffer_size) - return -1; + return AVERROR(ERANGE); d = av_mallocz(sizeof(DynBuffer) + io_buffer_size); if (!d) return AVERROR(ENOMEM); @@ -1396,7 +1367,7 @@ int avio_open_dyn_buf(AVIOContext **s) int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size) { if (max_packet_size <= 0) - return -1; + return AVERROR(EINVAL); return url_open_dyn_buf_internal(s, max_packet_size); } @@ -1408,15 +1379,31 @@ int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer) *pbuffer = NULL; return 0; } + d = s->opaque; + + if (!s->error && !d->size) { + *pbuffer = d->io_buffer; + return FFMAX(s->buf_ptr, s->buf_ptr_max) - s->buffer; + } avio_flush(s); - d = s->opaque; *pbuffer = d->buffer; return d->size; } +void ffio_reset_dyn_buf(AVIOContext *s) +{ + DynBuffer *d = s->opaque; + int max_packet_size = s->max_packet_size; + + ffio_init_context(s, d->io_buffer, d->io_buffer_size, 1, d, NULL, + s->write_packet, s->seek); + s->max_packet_size = max_packet_size; + d->pos = d->size = 0; +} + int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) { DynBuffer *d; @@ -1449,12 +1436,15 @@ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) void ffio_free_dyn_buf(AVIOContext **s) { - uint8_t *tmp; + DynBuffer *d; + if (!*s) return; - avio_close_dyn_buf(*s, &tmp); - av_free(tmp); - *s = NULL; + + d = (*s)->opaque; + av_free(d->buffer); + av_free(d); + avio_context_free(s); } static int null_buf_write(void *opaque, uint8_t *buf, int buf_size)