yading@11: /* yading@11: * buffered I/O yading@11: * Copyright (c) 2000,2001 Fabrice Bellard yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: #include "libavutil/crc.h" yading@11: #include "libavutil/dict.h" yading@11: #include "libavutil/intreadwrite.h" yading@11: #include "libavutil/log.h" yading@11: #include "libavutil/opt.h" yading@11: #include "libavutil/avassert.h" yading@11: #include "avformat.h" yading@11: #include "avio.h" yading@11: #include "avio_internal.h" yading@11: #include "internal.h" yading@11: #include "url.h" yading@11: #include yading@11: yading@11: #define IO_BUFFER_SIZE 32768 yading@11: yading@11: /** yading@11: * Do seeks within this distance ahead of the current buffer by skipping yading@11: * data instead of calling the protocol seek function, for seekable yading@11: * protocols. yading@11: */ yading@11: #define SHORT_SEEK_THRESHOLD 4096 yading@11: yading@11: static void *ffio_url_child_next(void *obj, void *prev) yading@11: { yading@11: AVIOContext *s = obj; yading@11: return prev ? NULL : s->opaque; yading@11: } yading@11: yading@11: static const AVClass *ffio_url_child_class_next(const AVClass *prev) yading@11: { yading@11: return prev ? NULL : &ffurl_context_class; yading@11: } yading@11: yading@11: static const AVOption ffio_url_options[] = { yading@11: { NULL }, yading@11: }; yading@11: yading@11: const AVClass ffio_url_class = { yading@11: .class_name = "AVIOContext", yading@11: .item_name = av_default_item_name, yading@11: .version = LIBAVUTIL_VERSION_INT, yading@11: .option = ffio_url_options, yading@11: .child_next = ffio_url_child_next, yading@11: .child_class_next = ffio_url_child_class_next, yading@11: }; yading@11: yading@11: static void fill_buffer(AVIOContext *s); yading@11: static int url_resetbuf(AVIOContext *s, int flags); yading@11: yading@11: int ffio_init_context(AVIOContext *s, yading@11: unsigned char *buffer, yading@11: int buffer_size, yading@11: int write_flag, yading@11: void *opaque, yading@11: int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), yading@11: int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), yading@11: int64_t (*seek)(void *opaque, int64_t offset, int whence)) yading@11: { yading@11: s->buffer = buffer; yading@11: s->buffer_size = buffer_size; yading@11: s->buf_ptr = buffer; yading@11: s->opaque = opaque; yading@11: s->direct = 0; yading@11: yading@11: url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); yading@11: yading@11: s->write_packet = write_packet; yading@11: s->read_packet = read_packet; yading@11: s->seek = seek; yading@11: s->pos = 0; yading@11: s->must_flush = 0; yading@11: s->eof_reached = 0; yading@11: s->error = 0; yading@11: s->seekable = AVIO_SEEKABLE_NORMAL; yading@11: s->max_packet_size = 0; yading@11: s->update_checksum = NULL; yading@11: yading@11: if (!read_packet && !write_flag) { yading@11: s->pos = buffer_size; yading@11: s->buf_end = s->buffer + buffer_size; yading@11: } yading@11: s->read_pause = NULL; yading@11: s->read_seek = NULL; yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: AVIOContext *avio_alloc_context( yading@11: unsigned char *buffer, yading@11: int buffer_size, yading@11: int write_flag, yading@11: void *opaque, yading@11: int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), yading@11: int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), yading@11: int64_t (*seek)(void *opaque, int64_t offset, int whence)) yading@11: { yading@11: AVIOContext *s = av_mallocz(sizeof(AVIOContext)); yading@11: if (!s) yading@11: return NULL; yading@11: ffio_init_context(s, buffer, buffer_size, write_flag, opaque, yading@11: read_packet, write_packet, seek); yading@11: return s; yading@11: } yading@11: yading@11: static void writeout(AVIOContext *s, const uint8_t *data, int len) yading@11: { yading@11: if (s->write_packet && !s->error) { yading@11: int ret = s->write_packet(s->opaque, (uint8_t *)data, len); yading@11: if (ret < 0) { yading@11: s->error = ret; yading@11: } yading@11: } yading@11: s->writeout_count ++; yading@11: s->pos += len; yading@11: } yading@11: yading@11: static void flush_buffer(AVIOContext *s) yading@11: { yading@11: if (s->buf_ptr > s->buffer) { yading@11: writeout(s, s->buffer, s->buf_ptr - s->buffer); yading@11: if (s->update_checksum) { yading@11: s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, yading@11: s->buf_ptr - s->checksum_ptr); yading@11: s->checksum_ptr = s->buffer; yading@11: } yading@11: } yading@11: s->buf_ptr = s->buffer; yading@11: } yading@11: yading@11: void avio_w8(AVIOContext *s, int b) yading@11: { yading@11: av_assert2(b>=-128 && b<=255); yading@11: *s->buf_ptr++ = b; yading@11: if (s->buf_ptr >= s->buf_end) yading@11: flush_buffer(s); yading@11: } yading@11: yading@11: void ffio_fill(AVIOContext *s, int b, int count) yading@11: { yading@11: while (count > 0) { yading@11: int len = FFMIN(s->buf_end - s->buf_ptr, count); yading@11: memset(s->buf_ptr, b, len); yading@11: s->buf_ptr += len; yading@11: yading@11: if (s->buf_ptr >= s->buf_end) yading@11: flush_buffer(s); yading@11: yading@11: count -= len; yading@11: } yading@11: } yading@11: yading@11: void avio_write(AVIOContext *s, const unsigned char *buf, int size) yading@11: { yading@11: if (s->direct && !s->update_checksum) { yading@11: avio_flush(s); yading@11: writeout(s, buf, size); yading@11: return; yading@11: } yading@11: while (size > 0) { yading@11: int len = FFMIN(s->buf_end - s->buf_ptr, size); yading@11: memcpy(s->buf_ptr, buf, len); yading@11: s->buf_ptr += len; yading@11: yading@11: if (s->buf_ptr >= s->buf_end) yading@11: flush_buffer(s); yading@11: yading@11: buf += len; yading@11: size -= len; yading@11: } yading@11: } yading@11: yading@11: void avio_flush(AVIOContext *s) yading@11: { yading@11: flush_buffer(s); yading@11: s->must_flush = 0; yading@11: } yading@11: yading@11: int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) yading@11: { yading@11: int64_t offset1; yading@11: int64_t pos; yading@11: int force = whence & AVSEEK_FORCE; yading@11: whence &= ~AVSEEK_FORCE; yading@11: yading@11: if(!s) yading@11: return AVERROR(EINVAL); yading@11: yading@11: pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer)); yading@11: yading@11: if (whence != SEEK_CUR && whence != SEEK_SET) yading@11: return AVERROR(EINVAL); yading@11: yading@11: if (whence == SEEK_CUR) { yading@11: offset1 = pos + (s->buf_ptr - s->buffer); yading@11: if (offset == 0) yading@11: return offset1; yading@11: offset += offset1; yading@11: } yading@11: offset1 = offset - pos; yading@11: if (!s->must_flush && (!s->direct || !s->seek) && yading@11: offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) { yading@11: /* can do the seek inside the buffer */ yading@11: s->buf_ptr = s->buffer + offset1; yading@11: } else if ((!s->seekable || yading@11: offset1 <= s->buf_end + SHORT_SEEK_THRESHOLD - s->buffer) && yading@11: !s->write_flag && offset1 >= 0 && yading@11: (!s->direct || !s->seek) && yading@11: (whence != SEEK_END || force)) { yading@11: while(s->pos < offset && !s->eof_reached) yading@11: fill_buffer(s); yading@11: if (s->eof_reached) yading@11: return AVERROR_EOF; yading@11: s->buf_ptr = s->buf_end + offset - s->pos; yading@11: } else { yading@11: int64_t res; yading@11: yading@11: if (s->write_flag) { yading@11: flush_buffer(s); yading@11: s->must_flush = 1; yading@11: } yading@11: if (!s->seek) yading@11: return AVERROR(EPIPE); yading@11: if ((res = s->seek(s->opaque, offset, SEEK_SET)) < 0) yading@11: return res; yading@11: s->seek_count ++; yading@11: if (!s->write_flag) yading@11: s->buf_end = s->buffer; yading@11: s->buf_ptr = s->buffer; yading@11: s->pos = offset; yading@11: } yading@11: s->eof_reached = 0; yading@11: return offset; yading@11: } yading@11: yading@11: int64_t avio_skip(AVIOContext *s, int64_t offset) yading@11: { yading@11: return avio_seek(s, offset, SEEK_CUR); yading@11: } yading@11: yading@11: int64_t avio_size(AVIOContext *s) yading@11: { yading@11: int64_t size; yading@11: yading@11: if (!s) yading@11: return AVERROR(EINVAL); yading@11: yading@11: if (!s->seek) yading@11: return AVERROR(ENOSYS); yading@11: size = s->seek(s->opaque, 0, AVSEEK_SIZE); yading@11: if (size < 0) { yading@11: if ((size = s->seek(s->opaque, -1, SEEK_END)) < 0) yading@11: return size; yading@11: size++; yading@11: s->seek(s->opaque, s->pos, SEEK_SET); yading@11: } yading@11: return size; yading@11: } yading@11: yading@11: int url_feof(AVIOContext *s) yading@11: { yading@11: if(!s) yading@11: return 0; yading@11: if(s->eof_reached){ yading@11: s->eof_reached=0; yading@11: fill_buffer(s); yading@11: } yading@11: return s->eof_reached; yading@11: } yading@11: yading@11: void avio_wl32(AVIOContext *s, unsigned int val) yading@11: { yading@11: avio_w8(s, (uint8_t) val ); yading@11: avio_w8(s, (uint8_t)(val >> 8 )); yading@11: avio_w8(s, (uint8_t)(val >> 16)); yading@11: avio_w8(s, val >> 24 ); yading@11: } yading@11: yading@11: void avio_wb32(AVIOContext *s, unsigned int val) yading@11: { yading@11: avio_w8(s, val >> 24 ); yading@11: avio_w8(s, (uint8_t)(val >> 16)); yading@11: avio_w8(s, (uint8_t)(val >> 8 )); yading@11: avio_w8(s, (uint8_t) val ); yading@11: } yading@11: yading@11: int avio_put_str(AVIOContext *s, const char *str) yading@11: { yading@11: int len = 1; yading@11: if (str) { yading@11: len += strlen(str); yading@11: avio_write(s, (const unsigned char *) str, len); yading@11: } else yading@11: avio_w8(s, 0); yading@11: return len; yading@11: } yading@11: yading@11: int avio_put_str16le(AVIOContext *s, const char *str) yading@11: { yading@11: const uint8_t *q = str; yading@11: int ret = 0; yading@11: yading@11: while (*q) { yading@11: uint32_t ch; yading@11: uint16_t tmp; yading@11: yading@11: GET_UTF8(ch, *q++, break;) yading@11: PUT_UTF16(ch, tmp, avio_wl16(s, tmp); ret += 2;) yading@11: } yading@11: avio_wl16(s, 0); yading@11: ret += 2; yading@11: return ret; yading@11: } yading@11: yading@11: int ff_get_v_length(uint64_t val) yading@11: { yading@11: int i = 1; yading@11: yading@11: while (val >>= 7) yading@11: i++; yading@11: yading@11: return i; yading@11: } yading@11: yading@11: void ff_put_v(AVIOContext *bc, uint64_t val) yading@11: { yading@11: int i = ff_get_v_length(val); yading@11: yading@11: while (--i > 0) yading@11: avio_w8(bc, 128 | (uint8_t)(val >> (7*i))); yading@11: yading@11: avio_w8(bc, val & 127); yading@11: } yading@11: yading@11: void avio_wl64(AVIOContext *s, uint64_t val) yading@11: { yading@11: avio_wl32(s, (uint32_t)(val & 0xffffffff)); yading@11: avio_wl32(s, (uint32_t)(val >> 32)); yading@11: } yading@11: yading@11: void avio_wb64(AVIOContext *s, uint64_t val) yading@11: { yading@11: avio_wb32(s, (uint32_t)(val >> 32)); yading@11: avio_wb32(s, (uint32_t)(val & 0xffffffff)); yading@11: } yading@11: yading@11: void avio_wl16(AVIOContext *s, unsigned int val) yading@11: { yading@11: avio_w8(s, (uint8_t)val); yading@11: avio_w8(s, (int)val >> 8); yading@11: } yading@11: yading@11: void avio_wb16(AVIOContext *s, unsigned int val) yading@11: { yading@11: avio_w8(s, (int)val >> 8); yading@11: avio_w8(s, (uint8_t)val); yading@11: } yading@11: yading@11: void avio_wl24(AVIOContext *s, unsigned int val) yading@11: { yading@11: avio_wl16(s, val & 0xffff); yading@11: avio_w8(s, (int)val >> 16); yading@11: } yading@11: yading@11: void avio_wb24(AVIOContext *s, unsigned int val) yading@11: { yading@11: avio_wb16(s, (int)val >> 8); yading@11: avio_w8(s, (uint8_t)val); yading@11: } yading@11: yading@11: /* Input stream */ yading@11: yading@11: static void fill_buffer(AVIOContext *s) yading@11: { yading@11: uint8_t *dst = !s->max_packet_size && yading@11: s->buf_end - s->buffer < s->buffer_size ? yading@11: s->buf_end : s->buffer; yading@11: int len = s->buffer_size - (dst - s->buffer); yading@11: int max_buffer_size = s->max_packet_size ? yading@11: s->max_packet_size : IO_BUFFER_SIZE; yading@11: yading@11: /* can't fill the buffer without read_packet, just set EOF if appropriate */ yading@11: if (!s->read_packet && s->buf_ptr >= s->buf_end) yading@11: s->eof_reached = 1; yading@11: yading@11: /* no need to do anything if EOF already reached */ yading@11: if (s->eof_reached) yading@11: return; yading@11: yading@11: if (s->update_checksum && dst == s->buffer) { yading@11: if (s->buf_end > s->checksum_ptr) yading@11: s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, yading@11: s->buf_end - s->checksum_ptr); yading@11: s->checksum_ptr = s->buffer; yading@11: } yading@11: yading@11: /* make buffer smaller in case it ended up large after probing */ yading@11: if (s->read_packet && s->buffer_size > max_buffer_size) { yading@11: ffio_set_buf_size(s, max_buffer_size); yading@11: yading@11: s->checksum_ptr = dst = s->buffer; yading@11: len = s->buffer_size; yading@11: } yading@11: yading@11: if (s->read_packet) yading@11: len = s->read_packet(s->opaque, dst, len); yading@11: else yading@11: len = 0; yading@11: if (len <= 0) { yading@11: /* do not modify buffer if EOF reached so that a seek back can yading@11: be done without rereading data */ yading@11: s->eof_reached = 1; yading@11: if (len < 0) yading@11: s->error = len; yading@11: } else { yading@11: s->pos += len; yading@11: s->buf_ptr = dst; yading@11: s->buf_end = dst + len; yading@11: s->bytes_read += len; yading@11: } yading@11: } yading@11: yading@11: unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, yading@11: unsigned int len) yading@11: { yading@11: return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf, len); yading@11: } yading@11: yading@11: unsigned long ffio_get_checksum(AVIOContext *s) yading@11: { yading@11: s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, yading@11: s->buf_ptr - s->checksum_ptr); yading@11: s->update_checksum = NULL; yading@11: return s->checksum; yading@11: } yading@11: yading@11: void ffio_init_checksum(AVIOContext *s, yading@11: unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), yading@11: unsigned long checksum) yading@11: { yading@11: s->update_checksum = update_checksum; yading@11: if (s->update_checksum) { yading@11: s->checksum = checksum; yading@11: s->checksum_ptr = s->buf_ptr; yading@11: } yading@11: } yading@11: yading@11: /* XXX: put an inline version */ yading@11: int avio_r8(AVIOContext *s) yading@11: { yading@11: if (s->buf_ptr >= s->buf_end) yading@11: fill_buffer(s); yading@11: if (s->buf_ptr < s->buf_end) yading@11: return *s->buf_ptr++; yading@11: return 0; yading@11: } yading@11: yading@11: int avio_read(AVIOContext *s, unsigned char *buf, int size) yading@11: { yading@11: int len, size1; yading@11: yading@11: size1 = size; yading@11: while (size > 0) { yading@11: len = s->buf_end - s->buf_ptr; yading@11: if (len > size) yading@11: len = size; yading@11: if (len == 0 || s->write_flag) { yading@11: if((s->direct || size > s->buffer_size) && !s->update_checksum){ yading@11: if(s->read_packet) yading@11: len = s->read_packet(s->opaque, buf, size); yading@11: if (len <= 0) { yading@11: /* do not modify buffer if EOF reached so that a seek back can yading@11: be done without rereading data */ yading@11: s->eof_reached = 1; yading@11: if(len<0) yading@11: s->error= len; yading@11: break; yading@11: } else { yading@11: s->pos += len; yading@11: s->bytes_read += len; yading@11: size -= len; yading@11: buf += len; yading@11: s->buf_ptr = s->buffer; yading@11: s->buf_end = s->buffer/* + len*/; yading@11: } yading@11: } else { yading@11: fill_buffer(s); yading@11: len = s->buf_end - s->buf_ptr; yading@11: if (len == 0) yading@11: break; yading@11: } yading@11: } else { yading@11: memcpy(buf, s->buf_ptr, len); yading@11: buf += len; yading@11: s->buf_ptr += len; yading@11: size -= len; yading@11: } yading@11: } yading@11: if (size1 == size) { yading@11: if (s->error) return s->error; yading@11: if (url_feof(s)) return AVERROR_EOF; yading@11: } yading@11: return size1 - size; yading@11: } yading@11: yading@11: int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size) yading@11: { yading@11: int len; yading@11: yading@11: if (size < 0) yading@11: return -1; yading@11: yading@11: if (s->read_packet && s->write_flag) { yading@11: len = s->read_packet(s->opaque, buf, size); yading@11: if (len > 0) yading@11: s->pos += len; yading@11: return len; yading@11: } yading@11: yading@11: len = s->buf_end - s->buf_ptr; yading@11: if (len == 0) { yading@11: /* Reset the buf_end pointer to the start of the buffer, to make sure yading@11: * the fill_buffer call tries to read as much data as fits into the yading@11: * full buffer, instead of just what space is left after buf_end. yading@11: * This avoids returning partial packets at the end of the buffer, yading@11: * for packet based inputs. yading@11: */ yading@11: s->buf_end = s->buf_ptr = s->buffer; yading@11: fill_buffer(s); yading@11: len = s->buf_end - s->buf_ptr; yading@11: } yading@11: if (len > size) yading@11: len = size; yading@11: memcpy(buf, s->buf_ptr, len); yading@11: s->buf_ptr += len; yading@11: if (!len) { yading@11: if (s->error) return s->error; yading@11: if (url_feof(s)) return AVERROR_EOF; yading@11: } yading@11: return len; yading@11: } yading@11: yading@11: unsigned int avio_rl16(AVIOContext *s) yading@11: { yading@11: unsigned int val; yading@11: val = avio_r8(s); yading@11: val |= avio_r8(s) << 8; yading@11: return val; yading@11: } yading@11: yading@11: unsigned int avio_rl24(AVIOContext *s) yading@11: { yading@11: unsigned int val; yading@11: val = avio_rl16(s); yading@11: val |= avio_r8(s) << 16; yading@11: return val; yading@11: } yading@11: yading@11: unsigned int avio_rl32(AVIOContext *s) yading@11: { yading@11: unsigned int val; yading@11: val = avio_rl16(s); yading@11: val |= avio_rl16(s) << 16; yading@11: return val; yading@11: } yading@11: yading@11: uint64_t avio_rl64(AVIOContext *s) yading@11: { yading@11: uint64_t val; yading@11: val = (uint64_t)avio_rl32(s); yading@11: val |= (uint64_t)avio_rl32(s) << 32; yading@11: return val; yading@11: } yading@11: yading@11: unsigned int avio_rb16(AVIOContext *s) yading@11: { yading@11: unsigned int val; yading@11: val = avio_r8(s) << 8; yading@11: val |= avio_r8(s); yading@11: return val; yading@11: } yading@11: yading@11: unsigned int avio_rb24(AVIOContext *s) yading@11: { yading@11: unsigned int val; yading@11: val = avio_rb16(s) << 8; yading@11: val |= avio_r8(s); yading@11: return val; yading@11: } yading@11: unsigned int avio_rb32(AVIOContext *s) yading@11: { yading@11: unsigned int val; yading@11: val = avio_rb16(s) << 16; yading@11: val |= avio_rb16(s); yading@11: return val; yading@11: } yading@11: yading@11: int ff_get_line(AVIOContext *s, char *buf, int maxlen) yading@11: { yading@11: int i = 0; yading@11: char c; yading@11: yading@11: do { yading@11: c = avio_r8(s); yading@11: if (c && i < maxlen-1) yading@11: buf[i++] = c; yading@11: } while (c != '\n' && c); yading@11: yading@11: buf[i] = 0; yading@11: return i; yading@11: } yading@11: yading@11: int avio_get_str(AVIOContext *s, int maxlen, char *buf, int buflen) yading@11: { yading@11: int i; yading@11: yading@11: if (buflen <= 0) yading@11: return AVERROR(EINVAL); yading@11: // reserve 1 byte for terminating 0 yading@11: buflen = FFMIN(buflen - 1, maxlen); yading@11: for (i = 0; i < buflen; i++) yading@11: if (!(buf[i] = avio_r8(s))) yading@11: return i + 1; yading@11: buf[i] = 0; yading@11: for (; i < maxlen; i++) yading@11: if (!avio_r8(s)) yading@11: return i + 1; yading@11: return maxlen; yading@11: } yading@11: yading@11: #define GET_STR16(type, read) \ yading@11: int avio_get_str16 ##type(AVIOContext *pb, int maxlen, char *buf, int buflen)\ yading@11: {\ yading@11: char* q = buf;\ yading@11: int ret = 0;\ yading@11: if (buflen <= 0) \ yading@11: return AVERROR(EINVAL); \ yading@11: while (ret + 1 < maxlen) {\ yading@11: uint8_t tmp;\ yading@11: uint32_t ch;\ yading@11: GET_UTF16(ch, (ret += 2) <= maxlen ? read(pb) : 0, break;)\ yading@11: if (!ch)\ yading@11: break;\ yading@11: PUT_UTF8(ch, tmp, if (q - buf < buflen - 1) *q++ = tmp;)\ yading@11: }\ yading@11: *q = 0;\ yading@11: return ret;\ yading@11: }\ yading@11: yading@11: GET_STR16(le, avio_rl16) yading@11: GET_STR16(be, avio_rb16) yading@11: yading@11: #undef GET_STR16 yading@11: yading@11: uint64_t avio_rb64(AVIOContext *s) yading@11: { yading@11: uint64_t val; yading@11: val = (uint64_t)avio_rb32(s) << 32; yading@11: val |= (uint64_t)avio_rb32(s); yading@11: return val; yading@11: } yading@11: yading@11: uint64_t ffio_read_varlen(AVIOContext *bc){ yading@11: uint64_t val = 0; yading@11: int tmp; yading@11: yading@11: do{ yading@11: tmp = avio_r8(bc); yading@11: val= (val<<7) + (tmp&127); yading@11: }while(tmp&128); yading@11: return val; yading@11: } yading@11: yading@11: int ffio_fdopen(AVIOContext **s, URLContext *h) yading@11: { yading@11: uint8_t *buffer; yading@11: int buffer_size, max_packet_size; yading@11: yading@11: max_packet_size = h->max_packet_size; yading@11: if (max_packet_size) { yading@11: buffer_size = max_packet_size; /* no need to bufferize more than one packet */ yading@11: } else { yading@11: buffer_size = IO_BUFFER_SIZE; yading@11: } yading@11: buffer = av_malloc(buffer_size); yading@11: if (!buffer) yading@11: return AVERROR(ENOMEM); yading@11: yading@11: *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, h, yading@11: (void*)ffurl_read, (void*)ffurl_write, (void*)ffurl_seek); yading@11: if (!*s) { yading@11: av_free(buffer); yading@11: return AVERROR(ENOMEM); yading@11: } yading@11: (*s)->direct = h->flags & AVIO_FLAG_DIRECT; yading@11: (*s)->seekable = h->is_streamed ? 0 : AVIO_SEEKABLE_NORMAL; yading@11: (*s)->max_packet_size = max_packet_size; yading@11: if(h->prot) { yading@11: (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause; yading@11: (*s)->read_seek = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek; yading@11: } yading@11: (*s)->av_class = &ffio_url_class; yading@11: return 0; yading@11: } yading@11: yading@11: int ffio_set_buf_size(AVIOContext *s, int buf_size) yading@11: { yading@11: uint8_t *buffer; yading@11: buffer = av_malloc(buf_size); yading@11: if (!buffer) yading@11: return AVERROR(ENOMEM); yading@11: yading@11: av_free(s->buffer); yading@11: s->buffer = buffer; yading@11: s->buffer_size = buf_size; yading@11: s->buf_ptr = buffer; yading@11: url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); yading@11: return 0; yading@11: } yading@11: yading@11: static int url_resetbuf(AVIOContext *s, int flags) yading@11: { yading@11: av_assert1(flags == AVIO_FLAG_WRITE || flags == AVIO_FLAG_READ); yading@11: yading@11: if (flags & AVIO_FLAG_WRITE) { yading@11: s->buf_end = s->buffer + s->buffer_size; yading@11: s->write_flag = 1; yading@11: } else { yading@11: s->buf_end = s->buffer; yading@11: s->write_flag = 0; yading@11: } yading@11: return 0; yading@11: } yading@11: yading@11: int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **bufp, int buf_size) yading@11: { yading@11: int64_t buffer_start; yading@11: int buffer_size; yading@11: int overlap, new_size, alloc_size; yading@11: uint8_t *buf = *bufp; yading@11: yading@11: if (s->write_flag) { yading@11: av_freep(bufp); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: yading@11: buffer_size = s->buf_end - s->buffer; yading@11: yading@11: /* the buffers must touch or overlap */ yading@11: if ((buffer_start = s->pos - buffer_size) > buf_size) { yading@11: av_freep(bufp); yading@11: return AVERROR(EINVAL); yading@11: } yading@11: yading@11: overlap = buf_size - buffer_start; yading@11: new_size = buf_size + buffer_size - overlap; yading@11: yading@11: alloc_size = FFMAX(s->buffer_size, new_size); yading@11: if (alloc_size > buf_size) yading@11: if (!(buf = (*bufp) = av_realloc_f(buf, 1, alloc_size))) yading@11: return AVERROR(ENOMEM); yading@11: yading@11: if (new_size > buf_size) { yading@11: memcpy(buf + buf_size, s->buffer + overlap, buffer_size - overlap); yading@11: buf_size = new_size; yading@11: } yading@11: yading@11: av_free(s->buffer); yading@11: s->buf_ptr = s->buffer = buf; yading@11: s->buffer_size = alloc_size; yading@11: s->pos = buf_size; yading@11: s->buf_end = s->buf_ptr + buf_size; yading@11: s->eof_reached = 0; yading@11: s->must_flush = 0; yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: int avio_open(AVIOContext **s, const char *filename, int flags) yading@11: { yading@11: return avio_open2(s, filename, flags, NULL, NULL); yading@11: } yading@11: yading@11: int avio_open2(AVIOContext **s, const char *filename, int flags, yading@11: const AVIOInterruptCB *int_cb, AVDictionary **options) yading@11: { yading@11: URLContext *h; yading@11: int err; yading@11: yading@11: err = ffurl_open(&h, filename, flags, int_cb, options); yading@11: if (err < 0) yading@11: return err; yading@11: err = ffio_fdopen(s, h); yading@11: if (err < 0) { yading@11: ffurl_close(h); yading@11: return err; yading@11: } yading@11: return 0; yading@11: } yading@11: yading@11: int avio_close(AVIOContext *s) yading@11: { yading@11: URLContext *h; yading@11: yading@11: if (!s) yading@11: return 0; yading@11: yading@11: avio_flush(s); yading@11: h = s->opaque; yading@11: av_freep(&s->buffer); yading@11: if (s->write_flag) yading@11: av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count); yading@11: else yading@11: av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count); yading@11: av_free(s); yading@11: return ffurl_close(h); yading@11: } yading@11: yading@11: int avio_closep(AVIOContext **s) yading@11: { yading@11: int ret = avio_close(*s); yading@11: *s = NULL; yading@11: return ret; yading@11: } yading@11: yading@11: int avio_printf(AVIOContext *s, const char *fmt, ...) yading@11: { yading@11: va_list ap; yading@11: char buf[4096]; yading@11: int ret; yading@11: yading@11: va_start(ap, fmt); yading@11: ret = vsnprintf(buf, sizeof(buf), fmt, ap); yading@11: va_end(ap); yading@11: avio_write(s, buf, strlen(buf)); yading@11: return ret; yading@11: } yading@11: yading@11: int avio_pause(AVIOContext *s, int pause) yading@11: { yading@11: if (!s->read_pause) yading@11: return AVERROR(ENOSYS); yading@11: return s->read_pause(s->opaque, pause); yading@11: } yading@11: yading@11: int64_t avio_seek_time(AVIOContext *s, int stream_index, yading@11: int64_t timestamp, int flags) yading@11: { yading@11: URLContext *h = s->opaque; yading@11: int64_t ret; yading@11: if (!s->read_seek) yading@11: return AVERROR(ENOSYS); yading@11: ret = s->read_seek(h, stream_index, timestamp, flags); yading@11: if (ret >= 0) { yading@11: int64_t pos; yading@11: s->buf_ptr = s->buf_end; // Flush buffer yading@11: pos = s->seek(h, 0, SEEK_CUR); yading@11: if (pos >= 0) yading@11: s->pos = pos; yading@11: else if (pos != AVERROR(ENOSYS)) yading@11: ret = pos; yading@11: } yading@11: return ret; yading@11: } yading@11: yading@11: /* output in a dynamic buffer */ yading@11: yading@11: typedef struct DynBuffer { yading@11: int pos, size, allocated_size; yading@11: uint8_t *buffer; yading@11: int io_buffer_size; yading@11: uint8_t io_buffer[1]; yading@11: } DynBuffer; yading@11: yading@11: static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size) yading@11: { yading@11: DynBuffer *d = opaque; yading@11: unsigned new_size, new_allocated_size; yading@11: yading@11: /* reallocate buffer if needed */ yading@11: new_size = d->pos + buf_size; yading@11: new_allocated_size = d->allocated_size; yading@11: if (new_size < d->pos || new_size > INT_MAX/2) yading@11: return -1; yading@11: while (new_size > new_allocated_size) { yading@11: if (!new_allocated_size) yading@11: new_allocated_size = new_size; yading@11: else yading@11: new_allocated_size += new_allocated_size / 2 + 1; yading@11: } yading@11: yading@11: if (new_allocated_size > d->allocated_size) { yading@11: d->buffer = av_realloc_f(d->buffer, 1, new_allocated_size); yading@11: if(d->buffer == NULL) yading@11: return AVERROR(ENOMEM); yading@11: d->allocated_size = new_allocated_size; yading@11: } yading@11: memcpy(d->buffer + d->pos, buf, buf_size); yading@11: d->pos = new_size; yading@11: if (d->pos > d->size) yading@11: d->size = d->pos; yading@11: return buf_size; yading@11: } yading@11: yading@11: static int dyn_packet_buf_write(void *opaque, uint8_t *buf, int buf_size) yading@11: { yading@11: unsigned char buf1[4]; yading@11: int ret; yading@11: yading@11: /* packetized write: output the header */ yading@11: AV_WB32(buf1, buf_size); yading@11: ret = dyn_buf_write(opaque, buf1, 4); yading@11: if (ret < 0) yading@11: return ret; yading@11: yading@11: /* then the data */ yading@11: return dyn_buf_write(opaque, buf, buf_size); yading@11: } yading@11: yading@11: static int64_t dyn_buf_seek(void *opaque, int64_t offset, int whence) yading@11: { yading@11: DynBuffer *d = opaque; yading@11: yading@11: if (whence == SEEK_CUR) yading@11: offset += d->pos; yading@11: else if (whence == SEEK_END) yading@11: offset += d->size; yading@11: if (offset < 0 || offset > 0x7fffffffLL) yading@11: return -1; yading@11: d->pos = offset; yading@11: return 0; yading@11: } yading@11: yading@11: static int url_open_dyn_buf_internal(AVIOContext **s, int max_packet_size) yading@11: { yading@11: DynBuffer *d; yading@11: unsigned io_buffer_size = max_packet_size ? max_packet_size : 1024; yading@11: yading@11: if (sizeof(DynBuffer) + io_buffer_size < io_buffer_size) yading@11: return -1; yading@11: d = av_mallocz(sizeof(DynBuffer) + io_buffer_size); yading@11: if (!d) yading@11: return AVERROR(ENOMEM); yading@11: d->io_buffer_size = io_buffer_size; yading@11: *s = avio_alloc_context(d->io_buffer, d->io_buffer_size, 1, d, NULL, yading@11: max_packet_size ? dyn_packet_buf_write : dyn_buf_write, yading@11: max_packet_size ? NULL : dyn_buf_seek); yading@11: if(!*s) { yading@11: av_free(d); yading@11: return AVERROR(ENOMEM); yading@11: } yading@11: (*s)->max_packet_size = max_packet_size; yading@11: return 0; yading@11: } yading@11: yading@11: int avio_open_dyn_buf(AVIOContext **s) yading@11: { yading@11: return url_open_dyn_buf_internal(s, 0); yading@11: } yading@11: yading@11: int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size) yading@11: { yading@11: if (max_packet_size <= 0) yading@11: return -1; yading@11: return url_open_dyn_buf_internal(s, max_packet_size); yading@11: } yading@11: yading@11: int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) yading@11: { yading@11: DynBuffer *d = s->opaque; yading@11: int size; yading@11: static const char padbuf[FF_INPUT_BUFFER_PADDING_SIZE] = {0}; yading@11: int padding = 0; yading@11: yading@11: /* don't attempt to pad fixed-size packet buffers */ yading@11: if (!s->max_packet_size) { yading@11: avio_write(s, padbuf, sizeof(padbuf)); yading@11: padding = FF_INPUT_BUFFER_PADDING_SIZE; yading@11: } yading@11: yading@11: avio_flush(s); yading@11: yading@11: *pbuffer = d->buffer; yading@11: size = d->size; yading@11: av_free(d); yading@11: av_free(s); yading@11: return size - padding; yading@11: }