aboutsummaryrefslogtreecommitdiff
path: root/libavformat/aviobuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/aviobuf.c')
-rw-r--r--libavformat/aviobuf.c499
1 files changed, 329 insertions, 170 deletions
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 5cb733d3d8..ef6a0d4e9b 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -2,28 +2,30 @@
* buffered I/O
* Copyright (c) 2000,2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/bprint.h"
#include "libavutil/crc.h"
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
#include "avformat.h"
#include "avio.h"
#include "avio_internal.h"
@@ -41,56 +43,26 @@
#define SHORT_SEEK_THRESHOLD 4096
typedef struct AVIOInternal {
- const AVClass *class;
-
- char *protocol_whitelist;
- char *protocol_blacklist;
-
URLContext *h;
- const URLProtocol **protocols;
} AVIOInternal;
-static void *io_priv_child_next(void *obj, void *prev)
-{
- AVIOInternal *internal = obj;
- return prev ? NULL : internal->h;
-}
-
-static const AVClass *io_priv_child_class_next(const AVClass *prev)
-{
- return prev ? NULL : &ffurl_context_class;
-}
-
-#define OFFSET(x) offsetof(AVIOInternal, x)
-static const AVOption io_priv_options[] = {
- { "protocol_whitelist", "A comma-separated list of allowed protocols",
- OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING },
- { "protocol_blacklist", "A comma-separated list of forbidden protocols",
- OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING },
- { NULL },
-};
-
-static const AVClass io_priv_class = {
- .class_name = "AVIOContext",
- .item_name = av_default_item_name,
- .version = LIBAVUTIL_VERSION_INT,
- .option = io_priv_options,
- .child_next = io_priv_child_next,
- .child_class_next = io_priv_child_class_next,
-};
-
static void *ff_avio_child_next(void *obj, void *prev)
{
AVIOContext *s = obj;
- return prev ? NULL : s->opaque;
+ AVIOInternal *internal = s->opaque;
+ return prev ? NULL : internal->h;
}
static const AVClass *ff_avio_child_class_next(const AVClass *prev)
{
- return prev ? NULL : &io_priv_class;
+ return prev ? NULL : &ffurl_context_class;
}
+#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 },
{ NULL },
};
@@ -116,9 +88,11 @@ int ffio_init_context(AVIOContext *s,
int64_t (*seek)(void *opaque, int64_t offset, int whence))
{
s->buffer = buffer;
+ s->orig_buffer_size =
s->buffer_size = buffer_size;
s->buf_ptr = buffer;
s->opaque = opaque;
+ s->direct = 0;
url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);
@@ -132,6 +106,7 @@ int ffio_init_context(AVIOContext *s,
s->seekable = seek ? AVIO_SEEKABLE_NORMAL : 0;
s->max_packet_size = 0;
s->update_checksum = NULL;
+ s->short_seek_threshold = SHORT_SEEK_THRESHOLD;
if (!read_packet && !write_flag) {
s->pos = buffer_size;
@@ -144,6 +119,7 @@ int ffio_init_context(AVIOContext *s,
s->ignore_boundary_point = 0;
s->current_type = AVIO_DATA_MARKER_UNKNOWN;
s->last_time = AV_NOPTS_VALUE;
+ s->short_seek_get = NULL;
return 0;
}
@@ -165,40 +141,48 @@ AVIOContext *avio_alloc_context(
return s;
}
-static void flush_buffer(AVIOContext *s)
+static void writeout(AVIOContext *s, const uint8_t *data, int len)
{
- if (s->buf_ptr > s->buffer) {
- if (!s->error) {
- int ret = 0;
- if (s->write_data_type)
- ret = s->write_data_type(s->opaque, s->buffer,
- s->buf_ptr - s->buffer,
- s->current_type,
- s->last_time);
- else if (s->write_packet)
- ret = s->write_packet(s->opaque, s->buffer,
- s->buf_ptr - s->buffer);
- if (ret < 0) {
- s->error = ret;
- }
+ if (!s->error) {
+ int ret = 0;
+ if (s->write_data_type)
+ ret = s->write_data_type(s->opaque, (uint8_t *)data,
+ len,
+ s->current_type,
+ s->last_time);
+ else if (s->write_packet)
+ ret = s->write_packet(s->opaque, (uint8_t *)data, len);
+ if (ret < 0) {
+ s->error = ret;
}
- if (s->current_type == AVIO_DATA_MARKER_SYNC_POINT ||
- s->current_type == AVIO_DATA_MARKER_BOUNDARY_POINT) {
- s->current_type = AVIO_DATA_MARKER_UNKNOWN;
- }
- s->last_time = AV_NOPTS_VALUE;
+ }
+ if (s->current_type == AVIO_DATA_MARKER_SYNC_POINT ||
+ s->current_type == AVIO_DATA_MARKER_BOUNDARY_POINT) {
+ s->current_type = AVIO_DATA_MARKER_UNKNOWN;
+ }
+ s->last_time = AV_NOPTS_VALUE;
+ s->writeout_count ++;
+ s->pos += len;
+}
+
+static void flush_buffer(AVIOContext *s)
+{
+ if (s->write_flag && s->buf_ptr > s->buffer) {
+ writeout(s, s->buffer, s->buf_ptr - s->buffer);
if (s->update_checksum) {
s->checksum = s->update_checksum(s->checksum, s->checksum_ptr,
s->buf_ptr - s->checksum_ptr);
s->checksum_ptr = s->buffer;
}
- s->pos += s->buf_ptr - s->buffer;
}
s->buf_ptr = s->buffer;
+ if (!s->write_flag)
+ s->buf_end = s->buffer;
}
void avio_w8(AVIOContext *s, int b)
{
+ av_assert2(b>=-128 && b<=255);
*s->buf_ptr++ = b;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
@@ -220,6 +204,11 @@ void ffio_fill(AVIOContext *s, int b, int count)
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
{
+ if (s->direct && !s->update_checksum) {
+ avio_flush(s);
+ writeout(s, buf, size);
+ return;
+ }
while (size > 0) {
int len = FFMIN(s->buf_end - s->buf_ptr, size);
memcpy(s->buf_ptr, buf, len);
@@ -244,12 +233,16 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
int64_t offset1;
int64_t pos;
int force = whence & AVSEEK_FORCE;
+ int buffer_size;
+ int short_seek;
whence &= ~AVSEEK_FORCE;
if(!s)
return AVERROR(EINVAL);
- pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer));
+ 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);
if (whence != SEEK_CUR && whence != SEEK_SET)
return AVERROR(EINVAL);
@@ -260,23 +253,46 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
return offset1;
offset += offset1;
}
- offset1 = offset - pos;
- if (!s->must_flush &&
- offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
+ 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;
+
+ offset1 = offset - pos; // "offset1" is the relative offset from the beginning of s->buffer
+ if (!s->must_flush && (!s->direct || !s->seek) &&
+ offset1 >= 0 && offset1 <= buffer_size - s->write_flag) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
} else if ((!(s->seekable & AVIO_SEEKABLE_NORMAL) ||
- offset1 <= s->buf_end + SHORT_SEEK_THRESHOLD - s->buffer) &&
+ offset1 <= buffer_size + short_seek) &&
!s->write_flag && offset1 >= 0 &&
+ (!s->direct || !s->seek) &&
(whence != SEEK_END || force)) {
while(s->pos < offset && !s->eof_reached)
fill_buffer(s);
if (s->eof_reached)
return AVERROR_EOF;
- s->buf_ptr = s->buf_end + offset - s->pos;
- } else {
+ s->buf_ptr = s->buf_end - (s->pos - offset);
+ } else if(!s->write_flag && offset1 < 0 && -offset1 < buffer_size>>1 && s->seek && offset > 0) {
int64_t res;
+ pos -= FFMIN(buffer_size>>1, pos);
+ if ((res = s->seek(s->opaque, pos, SEEK_SET)) < 0)
+ return res;
+ s->buf_end =
+ s->buf_ptr = s->buffer;
+ s->pos = pos;
+ s->eof_reached = 0;
+ fill_buffer(s);
+ return avio_seek(s, offset, SEEK_SET | force);
+ } else {
+ int64_t res;
if (s->write_flag) {
flush_buffer(s);
s->must_flush = 1;
@@ -285,6 +301,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
return AVERROR(EPIPE);
if ((res = s->seek(s->opaque, offset, SEEK_SET)) < 0)
return res;
+ s->seek_count ++;
if (!s->write_flag)
s->buf_end = s->buffer;
s->buf_ptr = s->buffer;
@@ -294,6 +311,11 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
return offset;
}
+int64_t avio_skip(AVIOContext *s, int64_t offset)
+{
+ return avio_seek(s, offset, SEEK_CUR);
+}
+
int64_t avio_size(AVIOContext *s)
{
int64_t size;
@@ -313,20 +335,38 @@ int64_t avio_size(AVIOContext *s)
return size;
}
+int avio_feof(AVIOContext *s)
+{
+ if(!s)
+ return 0;
+ if(s->eof_reached){
+ s->eof_reached=0;
+ fill_buffer(s);
+ }
+ return s->eof_reached;
+}
+
+#if FF_API_URL_FEOF
+int url_feof(AVIOContext *s)
+{
+ return avio_feof(s);
+}
+#endif
+
void avio_wl32(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val);
- avio_w8(s, val >> 8);
- avio_w8(s, val >> 16);
- avio_w8(s, val >> 24);
+ avio_w8(s, (uint8_t) val );
+ avio_w8(s, (uint8_t)(val >> 8 ));
+ avio_w8(s, (uint8_t)(val >> 16));
+ avio_w8(s, val >> 24 );
}
void avio_wb32(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val >> 24);
- avio_w8(s, val >> 16);
- avio_w8(s, val >> 8);
- avio_w8(s, val);
+ avio_w8(s, val >> 24 );
+ avio_w8(s, (uint8_t)(val >> 16));
+ avio_w8(s, (uint8_t)(val >> 8 ));
+ avio_w8(s, (uint8_t) val );
}
int avio_put_str(AVIOContext *s, const char *str)
@@ -340,26 +380,44 @@ int avio_put_str(AVIOContext *s, const char *str)
return len;
}
-#define PUT_STR16(type, write) \
- int avio_put_str16 ## type(AVIOContext * s, const char *str) \
- { \
- const uint8_t *q = str; \
- int ret = 0; \
- \
- while (*q) { \
- uint32_t ch; \
- uint16_t tmp; \
- \
- GET_UTF8(ch, *q++, break; ) \
- PUT_UTF16(ch, tmp, write(s, tmp); ret += 2; ) \
- } \
- write(s, 0); \
- ret += 2; \
- return ret; \
+static inline int put_str16(AVIOContext *s, const char *str, const int be)
+{
+ const uint8_t *q = str;
+ int ret = 0;
+ int err = 0;
+
+ while (*q) {
+ uint32_t ch;
+ uint16_t tmp;
+
+ GET_UTF8(ch, *q++, goto invalid;)
+ PUT_UTF16(ch, tmp, be ? avio_wb16(s, tmp) : avio_wl16(s, tmp);
+ ret += 2;)
+ continue;
+invalid:
+ av_log(s, AV_LOG_ERROR, "Invalid UTF8 sequence in avio_put_str16%s\n", be ? "be" : "le");
+ err = AVERROR(EINVAL);
+ if (!*(q-1))
+ break;
}
+ if (be)
+ avio_wb16(s, 0);
+ else
+ avio_wl16(s, 0);
+ if (err)
+ return err;
+ ret += 2;
+ return ret;
+}
-PUT_STR16(le, avio_wl16)
-PUT_STR16(be, avio_wb16)
+#define PUT_STR16(type, big_endian) \
+int avio_put_str16 ## type(AVIOContext *s, const char *str) \
+{ \
+return put_str16(s, str, big_endian); \
+}
+
+PUT_STR16(le, 0)
+PUT_STR16(be, 1)
#undef PUT_STR16
@@ -378,7 +436,7 @@ void ff_put_v(AVIOContext *bc, uint64_t val)
int i = ff_get_v_length(val);
while (--i > 0)
- avio_w8(bc, 128 | (val >> (7 * i)));
+ avio_w8(bc, 128 | (uint8_t)(val >> (7*i)));
avio_w8(bc, val & 127);
}
@@ -397,26 +455,26 @@ void avio_wb64(AVIOContext *s, uint64_t val)
void avio_wl16(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val);
- avio_w8(s, val >> 8);
+ avio_w8(s, (uint8_t)val);
+ avio_w8(s, (int)val >> 8);
}
void avio_wb16(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val >> 8);
- avio_w8(s, val);
+ avio_w8(s, (int)val >> 8);
+ avio_w8(s, (uint8_t)val);
}
void avio_wl24(AVIOContext *s, unsigned int val)
{
avio_wl16(s, val & 0xffff);
- avio_w8(s, val >> 16);
+ avio_w8(s, (int)val >> 16);
}
void avio_wb24(AVIOContext *s, unsigned int val)
{
- avio_wb16(s, val >> 8);
- avio_w8(s, val);
+ avio_wb16(s, (int)val >> 8);
+ avio_w8(s, (uint8_t)val);
}
void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type)
@@ -454,12 +512,11 @@ void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType typ
static void fill_buffer(AVIOContext *s)
{
- uint8_t *dst = !s->max_packet_size &&
- s->buf_end - s->buffer < s->buffer_size ?
- s->buf_end : s->buffer;
- int len = s->buffer_size - (dst - s->buffer);
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)
@@ -477,11 +534,16 @@ static void fill_buffer(AVIOContext *s)
}
/* make buffer smaller in case it ended up large after probing */
- if (s->buffer_size > max_buffer_size) {
- ffio_set_buf_size(s, max_buffer_size);
+ 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;
- len = s->buffer_size;
+ s->checksum_ptr = dst = s->buffer;
+ }
+ av_assert0(len >= s->orig_buffer_size);
+ len = s->orig_buffer_size;
}
if (s->read_packet)
@@ -498,6 +560,7 @@ static void fill_buffer(AVIOContext *s)
s->pos += len;
s->buf_ptr = dst;
s->buf_end = dst + len;
+ s->bytes_read += len;
}
}
@@ -507,6 +570,12 @@ unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf,
return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf, len);
}
+unsigned long ff_crcEDB88320_update(unsigned long checksum, const uint8_t *buf,
+ unsigned int len)
+{
+ return av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), checksum, buf, len);
+}
+
unsigned long ff_crcA001_update(unsigned long checksum, const uint8_t *buf,
unsigned int len)
{
@@ -548,13 +617,13 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
size1 = size;
while (size > 0) {
- len = s->buf_end - s->buf_ptr;
- if (len > size)
- len = size;
+ len = FFMIN(s->buf_end - s->buf_ptr, size);
if (len == 0 || s->write_flag) {
- if(size > s->buffer_size && !s->update_checksum){
+ if((s->direct || size > s->buffer_size) && !s->update_checksum) {
+ // bypass the buffer and read data directly into buf
if(s->read_packet)
len = s->read_packet(s->opaque, buf, size);
+
if (len <= 0) {
/* do not modify buffer if EOF reached so that a seek back can
be done without rereading data */
@@ -564,8 +633,10 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
break;
} else {
s->pos += len;
+ s->bytes_read += len;
size -= len;
buf += len;
+ // reset the buffer
s->buf_ptr = s->buffer;
s->buf_end = s->buffer/* + len*/;
}
@@ -583,8 +654,8 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
}
}
if (size1 == size) {
- if (s->error) return s->error;
- if (s->eof_reached) return AVERROR_EOF;
+ if (s->error) return s->error;
+ if (avio_feof(s)) return AVERROR_EOF;
}
return size1 - size;
}
@@ -640,8 +711,8 @@ int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size)
memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len;
if (!len) {
- if (s->error) return s->error;
- if (s->eof_reached) return AVERROR_EOF;
+ if (s->error) return s->error;
+ if (avio_feof(s)) return AVERROR_EOF;
}
return len;
}
@@ -710,7 +781,9 @@ int ff_get_line(AVIOContext *s, char *buf, int maxlen)
c = avio_r8(s);
if (c && i < maxlen-1)
buf[i++] = c;
- } while (c != '\n' && c);
+ } while (c != '\n' && c != '\r' && c);
+ if (c == '\r' && avio_r8(s) != '\n' && !avio_feof(s))
+ avio_skip(s, -1);
buf[i] = 0;
return i;
@@ -795,6 +868,12 @@ static int64_t io_seek(void *opaque, int64_t offset, int whence)
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;
@@ -831,16 +910,25 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
if (!internal)
goto fail;
- internal->class = &io_priv_class;
internal->h = h;
- av_opt_set_defaults(internal);
-
*s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE,
internal, io_read_packet, io_write_packet, io_seek);
if (!*s)
goto fail;
+ (*s)->protocol_whitelist = av_strdup(h->protocol_whitelist);
+ if (!(*s)->protocol_whitelist && h->protocol_whitelist) {
+ avio_closep(s);
+ goto fail;
+ }
+ (*s)->protocol_blacklist = av_strdup(h->protocol_blacklist);
+ if (!(*s)->protocol_blacklist && h->protocol_blacklist) {
+ avio_closep(s);
+ goto fail;
+ }
+ (*s)->direct = h->flags & AVIO_FLAG_DIRECT;
+
(*s)->seekable = h->is_streamed ? 0 : AVIO_SEEKABLE_NORMAL;
(*s)->max_packet_size = max_packet_size;
if(h->prot) {
@@ -850,16 +938,44 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
if (h->prot->url_read_seek)
(*s)->seekable |= AVIO_SEEKABLE_TIME;
}
+ (*s)->short_seek_get = io_short_seek;
(*s)->av_class = &ff_avio_class;
return 0;
fail:
- if (internal)
- av_opt_free(internal);
av_freep(&internal);
av_freep(&buffer);
return AVERROR(ENOMEM);
}
+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;
+
+ buf_size += s->buf_ptr - s->buffer + max_buffer_size;
+
+ if (buf_size < filled || 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;
+ return 0;
+}
+
int ffio_set_buf_size(AVIOContext *s, int buf_size)
{
uint8_t *buffer;
@@ -869,6 +985,7 @@ int ffio_set_buf_size(AVIOContext *s, int buf_size)
av_free(s->buffer);
s->buffer = buffer;
+ s->orig_buffer_size =
s->buffer_size = buf_size;
s->buf_ptr = buffer;
url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);
@@ -877,7 +994,7 @@ int ffio_set_buf_size(AVIOContext *s, int buf_size)
static int url_resetbuf(AVIOContext *s, int flags)
{
- assert(flags == AVIO_FLAG_WRITE || flags == AVIO_FLAG_READ);
+ av_assert1(flags == AVIO_FLAG_WRITE || flags == AVIO_FLAG_READ);
if (flags & AVIO_FLAG_WRITE) {
s->buf_end = s->buffer + s->buffer_size;
@@ -889,27 +1006,32 @@ static int url_resetbuf(AVIOContext *s, int flags)
return 0;
}
-int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char *buf, int buf_size)
+int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **bufp, int buf_size)
{
int64_t buffer_start;
int buffer_size;
int overlap, new_size, alloc_size;
+ uint8_t *buf = *bufp;
- if (s->write_flag)
+ if (s->write_flag) {
+ av_freep(bufp);
return AVERROR(EINVAL);
+ }
buffer_size = s->buf_end - s->buffer;
/* the buffers must touch or overlap */
- if ((buffer_start = s->pos - buffer_size) > buf_size)
+ if ((buffer_start = s->pos - buffer_size) > buf_size) {
+ av_freep(bufp);
return AVERROR(EINVAL);
+ }
overlap = buf_size - buffer_start;
new_size = buf_size + buffer_size - overlap;
alloc_size = FFMAX(s->buffer_size, new_size);
if (alloc_size > buf_size)
- if (!(buf = av_realloc(buf, alloc_size)))
+ if (!(buf = (*bufp) = av_realloc_f(buf, 1, alloc_size)))
return AVERROR(ENOMEM);
if (new_size > buf_size) {
@@ -933,54 +1055,35 @@ int avio_open(AVIOContext **s, const char *filename, int flags)
return avio_open2(s, filename, flags, NULL, NULL);
}
-int avio_open2(AVIOContext **s, const char *filename, int flags,
- const AVIOInterruptCB *int_cb, AVDictionary **options)
+int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags,
+ const AVIOInterruptCB *int_cb, AVDictionary **options,
+ const char *whitelist, const char *blacklist
+ )
{
- AVIOInternal *internal;
- const URLProtocol **protocols;
- char *proto_whitelist = NULL, *proto_blacklist = NULL;
- AVDictionaryEntry *e;
URLContext *h;
int err;
- if (options) {
- e = av_dict_get(*options, "protocol_whitelist", NULL, 0);
- if (e)
- proto_whitelist = e->value;
- e = av_dict_get(*options, "protocol_blacklist", NULL, 0);
- if (e)
- proto_blacklist = e->value;
- }
-
- protocols = ffurl_get_protocols(proto_whitelist, proto_blacklist);
- if (!protocols)
- return AVERROR(ENOMEM);
-
- err = ffurl_open(&h, filename, flags, int_cb, options, protocols, NULL);
- if (err < 0) {
- av_freep(&protocols);
+ err = ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist, blacklist, NULL);
+ if (err < 0)
return err;
- }
-
err = ffio_fdopen(s, h);
if (err < 0) {
ffurl_close(h);
- av_freep(&protocols);
return err;
}
+ return 0;
+}
- internal = (*s)->opaque;
- internal->protocols = protocols;
-
- if (options) {
- err = av_opt_set_dict(internal, options);
- if (err < 0) {
- avio_closep(s);
- return err;
- }
- }
+int avio_open2(AVIOContext **s, const char *filename, int flags,
+ const AVIOInterruptCB *int_cb, AVDictionary **options)
+{
+ return ffio_open_whitelist(s, filename, flags, int_cb, options, NULL, NULL);
+}
- return 0;
+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)
@@ -995,11 +1098,13 @@ int avio_close(AVIOContext *s)
internal = s->opaque;
h = internal->h;
- av_opt_free(internal);
-
- av_freep(&internal->protocols);
av_freep(&s->opaque);
av_freep(&s->buffer);
+ if (s->write_flag)
+ av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count);
+ else
+ av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count);
+ av_opt_free(s);
av_free(s);
return ffurl_close(h);
}
@@ -1014,7 +1119,7 @@ int avio_closep(AVIOContext **s)
int avio_printf(AVIOContext *s, const char *fmt, ...)
{
va_list ap;
- char buf[4096];
+ char buf[4096]; /* update doc entry in avio.h if changed */
int ret;
va_start(ap, fmt);
@@ -1050,6 +1155,43 @@ int64_t avio_seek_time(AVIOContext *s, int stream_index,
return ret;
}
+int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size)
+{
+ int ret;
+ char buf[1024];
+ while (max_size) {
+ ret = avio_read(h, buf, FFMIN(max_size, sizeof(buf)));
+ if (ret == AVERROR_EOF)
+ return 0;
+ if (ret <= 0)
+ return ret;
+ av_bprint_append_data(pb, buf, ret);
+ if (!av_bprint_is_complete(pb))
+ return AVERROR(ENOMEM);
+ max_size -= ret;
+ }
+ return 0;
+}
+
+int avio_accept(AVIOContext *s, AVIOContext **c)
+{
+ int ret;
+ AVIOInternal *internal = s->opaque;
+ URLContext *sc = internal->h;
+ URLContext *cc = NULL;
+ ret = ffurl_accept(sc, &cc);
+ if (ret < 0)
+ return ret;
+ return ffio_fdopen(c, cc);
+}
+
+int avio_handshake(AVIOContext *c)
+{
+ AVIOInternal *internal = c->opaque;
+ URLContext *cc = internal->h;
+ return ffurl_handshake(cc);
+}
+
/* output in a dynamic buffer */
typedef struct DynBuffer {
@@ -1155,6 +1297,23 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size)
return url_open_dyn_buf_internal(s, max_packet_size);
}
+int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
+{
+ DynBuffer *d;
+
+ if (!s) {
+ *pbuffer = NULL;
+ return 0;
+ }
+
+ avio_flush(s);
+
+ d = s->opaque;
+ *pbuffer = d->buffer;
+
+ return d->size;
+}
+
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
{
DynBuffer *d;