diff --git a/libavformat/utils.c b/libavformat/utils.c index b232902ab8..44d41d7f6b 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -251,6 +251,9 @@ AVInputFormat *av_find_input_format(const char *short_name) return NULL; } +/* an arbitrarily chosen "sane" max packet size -- 50M */ +#define SANE_CHUNK_SIZE (50000000) + int ffio_limit(AVIOContext *s, int size) { if(s->maxsize>=0){ @@ -271,43 +274,77 @@ int ffio_limit(AVIOContext *s, int size) return size; } -int av_get_packet(AVIOContext *s, AVPacket *pkt, int size) +/* + * Read the data in sane-sized chunks and append to pkt. + * Return the number of bytes read or an error. + */ +static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) { - int ret; - int orig_size = size; - size= ffio_limit(s, size); + int64_t chunk_size = size; + int orig_pos = pkt->pos; // av_grow_packet might reset pos + int orig_size = pkt->size; + int ret = 0; - ret= av_new_packet(pkt, size); + do { + int prev_size = pkt->size; + int read_size; - if(ret<0) - return ret; + /* + * When the caller requests a lot of data, limit it to the amount left + * in file or SANE_CHUNK_SIZE when it is not known + */ +#if 0 + if (size > SANE_CHUNK_SIZE) { + int64_t filesize = avio_size(s) - avio_tell(s); + chunk_size = FFMAX(filesize, SANE_CHUNK_SIZE); + } + read_size = FFMIN(size, chunk_size); +#else + read_size = size; + if (read_size > SANE_CHUNK_SIZE/10) { + read_size = ffio_limit(s, read_size); + // If filesize/maxsize is unknown, limit to SANE_CHUNK_SIZE + if (s->maxsize < 0) + read_size = FFMIN(read_size, SANE_CHUNK_SIZE); + } +#endif - pkt->pos= avio_tell(s); + ret = av_grow_packet(pkt, read_size); + if (ret < 0) + break; - ret= avio_read(s, pkt->data, size); - if(ret<=0) - av_free_packet(pkt); - else - av_shrink_packet(pkt, ret); - if (pkt->size < orig_size) + ret = avio_read(s, pkt->data + prev_size, read_size); + if (ret != read_size) { + av_shrink_packet(pkt, prev_size + FFMAX(ret, 0)); + break; + } + + size -= read_size; + } while (size > 0); + if (size > 0) pkt->flags |= AV_PKT_FLAG_CORRUPT; - return ret; + pkt->pos = orig_pos; + if (!pkt->size) + av_free_packet(pkt); + return pkt->size > orig_size ? pkt->size - orig_size : ret; +} + +int av_get_packet(AVIOContext *s, AVPacket *pkt, int size) +{ + av_init_packet(pkt); + pkt->data = NULL; + pkt->size = 0; + pkt->pos = avio_tell(s); + + return append_packet_chunked(s, pkt, size); } int av_append_packet(AVIOContext *s, AVPacket *pkt, int size) { - int ret; - int old_size; if (!pkt->size) return av_get_packet(s, pkt, size); - old_size = pkt->size; - ret = av_grow_packet(pkt, size); - if (ret < 0) - return ret; - ret = avio_read(s, pkt->data + old_size, size); - av_shrink_packet(pkt, old_size + FFMAX(ret, 0)); - return ret; + return append_packet_chunked(s, pkt, size); }