Libav

libavformat/aviobuf.c

Go to the documentation of this file.
00001 /*
00002  * Buffered I/O for ffmpeg system
00003  * Copyright (c) 2000,2001 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include "libavutil/crc.h"
00023 #include "libavutil/intreadwrite.h"
00024 #include "avformat.h"
00025 #include "avio.h"
00026 #include <stdarg.h>
00027 
00028 #define IO_BUFFER_SIZE 32768
00029 
00035 #define SHORT_SEEK_THRESHOLD 4096
00036 
00037 static void fill_buffer(ByteIOContext *s);
00038 #if LIBAVFORMAT_VERSION_MAJOR >= 53
00039 static int url_resetbuf(ByteIOContext *s, int flags);
00040 #endif
00041 
00042 int init_put_byte(ByteIOContext *s,
00043                   unsigned char *buffer,
00044                   int buffer_size,
00045                   int write_flag,
00046                   void *opaque,
00047                   int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
00048                   int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
00049                   int64_t (*seek)(void *opaque, int64_t offset, int whence))
00050 {
00051     s->buffer = buffer;
00052     s->buffer_size = buffer_size;
00053     s->buf_ptr = buffer;
00054     s->opaque = opaque;
00055     url_resetbuf(s, write_flag ? URL_WRONLY : URL_RDONLY);
00056     s->write_packet = write_packet;
00057     s->read_packet = read_packet;
00058     s->seek = seek;
00059     s->pos = 0;
00060     s->must_flush = 0;
00061     s->eof_reached = 0;
00062     s->error = 0;
00063     s->is_streamed = 0;
00064     s->max_packet_size = 0;
00065     s->update_checksum= NULL;
00066     if(!read_packet && !write_flag){
00067         s->pos = buffer_size;
00068         s->buf_end = s->buffer + buffer_size;
00069     }
00070     s->read_pause = NULL;
00071     s->read_seek  = NULL;
00072     return 0;
00073 }
00074 
00075 ByteIOContext *av_alloc_put_byte(
00076                   unsigned char *buffer,
00077                   int buffer_size,
00078                   int write_flag,
00079                   void *opaque,
00080                   int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
00081                   int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
00082                   int64_t (*seek)(void *opaque, int64_t offset, int whence))
00083 {
00084     ByteIOContext *s = av_mallocz(sizeof(ByteIOContext));
00085     init_put_byte(s, buffer, buffer_size, write_flag, opaque,
00086                   read_packet, write_packet, seek);
00087     return s;
00088 }
00089 
00090 static void flush_buffer(ByteIOContext *s)
00091 {
00092     if (s->buf_ptr > s->buffer) {
00093         if (s->write_packet && !s->error){
00094             int ret= s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer);
00095             if(ret < 0){
00096                 s->error = ret;
00097             }
00098         }
00099         if(s->update_checksum){
00100             s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
00101             s->checksum_ptr= s->buffer;
00102         }
00103         s->pos += s->buf_ptr - s->buffer;
00104     }
00105     s->buf_ptr = s->buffer;
00106 }
00107 
00108 void put_byte(ByteIOContext *s, int b)
00109 {
00110     *(s->buf_ptr)++ = b;
00111     if (s->buf_ptr >= s->buf_end)
00112         flush_buffer(s);
00113 }
00114 
00115 void put_buffer(ByteIOContext *s, const unsigned char *buf, int size)
00116 {
00117     while (size > 0) {
00118         int len = FFMIN(s->buf_end - s->buf_ptr, size);
00119         memcpy(s->buf_ptr, buf, len);
00120         s->buf_ptr += len;
00121 
00122         if (s->buf_ptr >= s->buf_end)
00123             flush_buffer(s);
00124 
00125         buf += len;
00126         size -= len;
00127     }
00128 }
00129 
00130 void put_flush_packet(ByteIOContext *s)
00131 {
00132     flush_buffer(s);
00133     s->must_flush = 0;
00134 }
00135 
00136 int64_t url_fseek(ByteIOContext *s, int64_t offset, int whence)
00137 {
00138     int64_t offset1;
00139     int64_t pos;
00140     int force = whence & AVSEEK_FORCE;
00141     whence &= ~AVSEEK_FORCE;
00142 
00143     if(!s)
00144         return AVERROR(EINVAL);
00145 
00146     pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer));
00147 
00148     if (whence != SEEK_CUR && whence != SEEK_SET)
00149         return AVERROR(EINVAL);
00150 
00151     if (whence == SEEK_CUR) {
00152         offset1 = pos + (s->buf_ptr - s->buffer);
00153         if (offset == 0)
00154             return offset1;
00155         offset += offset1;
00156     }
00157     offset1 = offset - pos;
00158     if (!s->must_flush &&
00159         offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) {
00160         /* can do the seek inside the buffer */
00161         s->buf_ptr = s->buffer + offset1;
00162     } else if ((s->is_streamed ||
00163                offset1 <= s->buf_end + SHORT_SEEK_THRESHOLD - s->buffer) &&
00164                !s->write_flag && offset1 >= 0 &&
00165               (whence != SEEK_END || force)) {
00166         while(s->pos < offset && !s->eof_reached)
00167             fill_buffer(s);
00168         if (s->eof_reached)
00169             return AVERROR_EOF;
00170         s->buf_ptr = s->buf_end + offset - s->pos;
00171     } else {
00172         int64_t res;
00173 
00174 #if CONFIG_MUXERS || CONFIG_NETWORK
00175         if (s->write_flag) {
00176             flush_buffer(s);
00177             s->must_flush = 1;
00178         }
00179 #endif /* CONFIG_MUXERS || CONFIG_NETWORK */
00180         if (!s->seek)
00181             return AVERROR(EPIPE);
00182         if ((res = s->seek(s->opaque, offset, SEEK_SET)) < 0)
00183             return res;
00184         if (!s->write_flag)
00185             s->buf_end = s->buffer;
00186         s->buf_ptr = s->buffer;
00187         s->pos = offset;
00188     }
00189     s->eof_reached = 0;
00190     return offset;
00191 }
00192 
00193 void url_fskip(ByteIOContext *s, int64_t offset)
00194 {
00195     url_fseek(s, offset, SEEK_CUR);
00196 }
00197 
00198 int64_t url_ftell(ByteIOContext *s)
00199 {
00200     return url_fseek(s, 0, SEEK_CUR);
00201 }
00202 
00203 int64_t url_fsize(ByteIOContext *s)
00204 {
00205     int64_t size;
00206 
00207     if(!s)
00208         return AVERROR(EINVAL);
00209 
00210     if (!s->seek)
00211         return AVERROR(ENOSYS);
00212     size = s->seek(s->opaque, 0, AVSEEK_SIZE);
00213     if(size<0){
00214         if ((size = s->seek(s->opaque, -1, SEEK_END)) < 0)
00215             return size;
00216         size++;
00217         s->seek(s->opaque, s->pos, SEEK_SET);
00218     }
00219     return size;
00220 }
00221 
00222 int url_feof(ByteIOContext *s)
00223 {
00224     if(!s)
00225         return 0;
00226     return s->eof_reached;
00227 }
00228 
00229 int url_ferror(ByteIOContext *s)
00230 {
00231     if(!s)
00232         return 0;
00233     return s->error;
00234 }
00235 
00236 void put_le32(ByteIOContext *s, unsigned int val)
00237 {
00238     put_byte(s, val);
00239     put_byte(s, val >> 8);
00240     put_byte(s, val >> 16);
00241     put_byte(s, val >> 24);
00242 }
00243 
00244 void put_be32(ByteIOContext *s, unsigned int val)
00245 {
00246     put_byte(s, val >> 24);
00247     put_byte(s, val >> 16);
00248     put_byte(s, val >> 8);
00249     put_byte(s, val);
00250 }
00251 
00252 void put_strz(ByteIOContext *s, const char *str)
00253 {
00254     if (str)
00255         put_buffer(s, (const unsigned char *) str, strlen(str) + 1);
00256     else
00257         put_byte(s, 0);
00258 }
00259 
00260 void put_le64(ByteIOContext *s, uint64_t val)
00261 {
00262     put_le32(s, (uint32_t)(val & 0xffffffff));
00263     put_le32(s, (uint32_t)(val >> 32));
00264 }
00265 
00266 void put_be64(ByteIOContext *s, uint64_t val)
00267 {
00268     put_be32(s, (uint32_t)(val >> 32));
00269     put_be32(s, (uint32_t)(val & 0xffffffff));
00270 }
00271 
00272 void put_le16(ByteIOContext *s, unsigned int val)
00273 {
00274     put_byte(s, val);
00275     put_byte(s, val >> 8);
00276 }
00277 
00278 void put_be16(ByteIOContext *s, unsigned int val)
00279 {
00280     put_byte(s, val >> 8);
00281     put_byte(s, val);
00282 }
00283 
00284 void put_le24(ByteIOContext *s, unsigned int val)
00285 {
00286     put_le16(s, val & 0xffff);
00287     put_byte(s, val >> 16);
00288 }
00289 
00290 void put_be24(ByteIOContext *s, unsigned int val)
00291 {
00292     put_be16(s, val >> 8);
00293     put_byte(s, val);
00294 }
00295 
00296 void put_tag(ByteIOContext *s, const char *tag)
00297 {
00298     while (*tag) {
00299         put_byte(s, *tag++);
00300     }
00301 }
00302 
00303 /* Input stream */
00304 
00305 static void fill_buffer(ByteIOContext *s)
00306 {
00307     uint8_t *dst= !s->max_packet_size && s->buf_end - s->buffer < s->buffer_size ? s->buf_ptr : s->buffer;
00308     int len= s->buffer_size - (dst - s->buffer);
00309     int max_buffer_size = s->max_packet_size ? s->max_packet_size : IO_BUFFER_SIZE;
00310 
00311     assert(s->buf_ptr == s->buf_end);
00312 
00313     /* no need to do anything if EOF already reached */
00314     if (s->eof_reached)
00315         return;
00316 
00317     if(s->update_checksum && dst == s->buffer){
00318         if(s->buf_end > s->checksum_ptr)
00319             s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_end - s->checksum_ptr);
00320         s->checksum_ptr= s->buffer;
00321     }
00322 
00323     /* make buffer smaller in case it ended up large after probing */
00324     if (s->buffer_size > max_buffer_size) {
00325         url_setbufsize(s, max_buffer_size);
00326 
00327         s->checksum_ptr = dst = s->buffer;
00328         len = s->buffer_size;
00329     }
00330 
00331     if(s->read_packet)
00332         len = s->read_packet(s->opaque, dst, len);
00333     else
00334         len = 0;
00335     if (len <= 0) {
00336         /* do not modify buffer if EOF reached so that a seek back can
00337            be done without rereading data */
00338         s->eof_reached = 1;
00339         if(len<0)
00340             s->error= len;
00341     } else {
00342         s->pos += len;
00343         s->buf_ptr = dst;
00344         s->buf_end = dst + len;
00345     }
00346 }
00347 
00348 unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf,
00349                                     unsigned int len)
00350 {
00351     return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf, len);
00352 }
00353 
00354 unsigned long get_checksum(ByteIOContext *s)
00355 {
00356     s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
00357     s->update_checksum= NULL;
00358     return s->checksum;
00359 }
00360 
00361 void init_checksum(ByteIOContext *s,
00362                    unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len),
00363                    unsigned long checksum)
00364 {
00365     s->update_checksum= update_checksum;
00366     if(s->update_checksum){
00367         s->checksum= checksum;
00368         s->checksum_ptr= s->buf_ptr;
00369     }
00370 }
00371 
00372 /* XXX: put an inline version */
00373 int get_byte(ByteIOContext *s)
00374 {
00375     if (s->buf_ptr < s->buf_end) {
00376         return *s->buf_ptr++;
00377     } else {
00378         fill_buffer(s);
00379         if (s->buf_ptr < s->buf_end)
00380             return *s->buf_ptr++;
00381         else
00382             return 0;
00383     }
00384 }
00385 
00386 int url_fgetc(ByteIOContext *s)
00387 {
00388     if (s->buf_ptr < s->buf_end) {
00389         return *s->buf_ptr++;
00390     } else {
00391         fill_buffer(s);
00392         if (s->buf_ptr < s->buf_end)
00393             return *s->buf_ptr++;
00394         else
00395             return URL_EOF;
00396     }
00397 }
00398 
00399 int get_buffer(ByteIOContext *s, unsigned char *buf, int size)
00400 {
00401     int len, size1;
00402 
00403     size1 = size;
00404     while (size > 0) {
00405         len = s->buf_end - s->buf_ptr;
00406         if (len > size)
00407             len = size;
00408         if (len == 0) {
00409             if(size > s->buffer_size && !s->update_checksum){
00410                 if(s->read_packet)
00411                     len = s->read_packet(s->opaque, buf, size);
00412                 if (len <= 0) {
00413                     /* do not modify buffer if EOF reached so that a seek back can
00414                     be done without rereading data */
00415                     s->eof_reached = 1;
00416                     if(len<0)
00417                         s->error= len;
00418                     break;
00419                 } else {
00420                     s->pos += len;
00421                     size -= len;
00422                     buf += len;
00423                     s->buf_ptr = s->buffer;
00424                     s->buf_end = s->buffer/* + len*/;
00425                 }
00426             }else{
00427                 fill_buffer(s);
00428                 len = s->buf_end - s->buf_ptr;
00429                 if (len == 0)
00430                     break;
00431             }
00432         } else {
00433             memcpy(buf, s->buf_ptr, len);
00434             buf += len;
00435             s->buf_ptr += len;
00436             size -= len;
00437         }
00438     }
00439     if (size1 == size) {
00440         if (url_ferror(s)) return url_ferror(s);
00441         if (url_feof(s))   return AVERROR_EOF;
00442     }
00443     return size1 - size;
00444 }
00445 
00446 int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size)
00447 {
00448     int len;
00449 
00450     if(size<0)
00451         return -1;
00452 
00453     len = s->buf_end - s->buf_ptr;
00454     if (len == 0) {
00455         fill_buffer(s);
00456         len = s->buf_end - s->buf_ptr;
00457     }
00458     if (len > size)
00459         len = size;
00460     memcpy(buf, s->buf_ptr, len);
00461     s->buf_ptr += len;
00462     if (!len) {
00463         if (url_ferror(s)) return url_ferror(s);
00464         if (url_feof(s))   return AVERROR_EOF;
00465     }
00466     return len;
00467 }
00468 
00469 unsigned int get_le16(ByteIOContext *s)
00470 {
00471     unsigned int val;
00472     val = get_byte(s);
00473     val |= get_byte(s) << 8;
00474     return val;
00475 }
00476 
00477 unsigned int get_le24(ByteIOContext *s)
00478 {
00479     unsigned int val;
00480     val = get_le16(s);
00481     val |= get_byte(s) << 16;
00482     return val;
00483 }
00484 
00485 unsigned int get_le32(ByteIOContext *s)
00486 {
00487     unsigned int val;
00488     val = get_le16(s);
00489     val |= get_le16(s) << 16;
00490     return val;
00491 }
00492 
00493 uint64_t get_le64(ByteIOContext *s)
00494 {
00495     uint64_t val;
00496     val = (uint64_t)get_le32(s);
00497     val |= (uint64_t)get_le32(s) << 32;
00498     return val;
00499 }
00500 
00501 unsigned int get_be16(ByteIOContext *s)
00502 {
00503     unsigned int val;
00504     val = get_byte(s) << 8;
00505     val |= get_byte(s);
00506     return val;
00507 }
00508 
00509 unsigned int get_be24(ByteIOContext *s)
00510 {
00511     unsigned int val;
00512     val = get_be16(s) << 8;
00513     val |= get_byte(s);
00514     return val;
00515 }
00516 unsigned int get_be32(ByteIOContext *s)
00517 {
00518     unsigned int val;
00519     val = get_be16(s) << 16;
00520     val |= get_be16(s);
00521     return val;
00522 }
00523 
00524 char *get_strz(ByteIOContext *s, char *buf, int maxlen)
00525 {
00526     int i = 0;
00527     char c;
00528 
00529     while ((c = get_byte(s))) {
00530         if (i < maxlen-1)
00531             buf[i++] = c;
00532     }
00533 
00534     buf[i] = 0; /* Ensure null terminated, but may be truncated */
00535 
00536     return buf;
00537 }
00538 
00539 uint64_t get_be64(ByteIOContext *s)
00540 {
00541     uint64_t val;
00542     val = (uint64_t)get_be32(s) << 32;
00543     val |= (uint64_t)get_be32(s);
00544     return val;
00545 }
00546 
00547 uint64_t ff_get_v(ByteIOContext *bc){
00548     uint64_t val = 0;
00549     int tmp;
00550 
00551     do{
00552         tmp = get_byte(bc);
00553         val= (val<<7) + (tmp&127);
00554     }while(tmp&128);
00555     return val;
00556 }
00557 
00558 int url_fdopen(ByteIOContext **s, URLContext *h)
00559 {
00560     uint8_t *buffer;
00561     int buffer_size, max_packet_size;
00562 
00563     max_packet_size = url_get_max_packet_size(h);
00564     if (max_packet_size) {
00565         buffer_size = max_packet_size; /* no need to bufferize more than one packet */
00566     } else {
00567         buffer_size = IO_BUFFER_SIZE;
00568     }
00569     buffer = av_malloc(buffer_size);
00570     if (!buffer)
00571         return AVERROR(ENOMEM);
00572 
00573     *s = av_mallocz(sizeof(ByteIOContext));
00574     if(!*s) {
00575         av_free(buffer);
00576         return AVERROR(ENOMEM);
00577     }
00578 
00579     if (init_put_byte(*s, buffer, buffer_size,
00580                       (h->flags & URL_WRONLY || h->flags & URL_RDWR), h,
00581                       url_read, url_write, url_seek) < 0) {
00582         av_free(buffer);
00583         av_freep(s);
00584         return AVERROR(EIO);
00585     }
00586     (*s)->is_streamed = h->is_streamed;
00587     (*s)->max_packet_size = max_packet_size;
00588     if(h->prot) {
00589         (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause;
00590         (*s)->read_seek  = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek;
00591     }
00592     return 0;
00593 }
00594 
00595 int url_setbufsize(ByteIOContext *s, int buf_size)
00596 {
00597     uint8_t *buffer;
00598     buffer = av_malloc(buf_size);
00599     if (!buffer)
00600         return AVERROR(ENOMEM);
00601 
00602     av_free(s->buffer);
00603     s->buffer = buffer;
00604     s->buffer_size = buf_size;
00605     s->buf_ptr = buffer;
00606     url_resetbuf(s, s->write_flag ? URL_WRONLY : URL_RDONLY);
00607     return 0;
00608 }
00609 
00610 #if LIBAVFORMAT_VERSION_MAJOR < 53
00611 int url_resetbuf(ByteIOContext *s, int flags)
00612 #else
00613 static int url_resetbuf(ByteIOContext *s, int flags)
00614 #endif
00615 {
00616 #if LIBAVFORMAT_VERSION_MAJOR < 53
00617     URLContext *h = s->opaque;
00618     if ((flags & URL_RDWR) || (h && h->flags != flags && !h->flags & URL_RDWR))
00619         return AVERROR(EINVAL);
00620 #else
00621     assert(flags == URL_WRONLY || flags == URL_RDONLY);
00622 #endif
00623 
00624     if (flags & URL_WRONLY) {
00625         s->buf_end = s->buffer + s->buffer_size;
00626         s->write_flag = 1;
00627     } else {
00628         s->buf_end = s->buffer;
00629         s->write_flag = 0;
00630     }
00631     return 0;
00632 }
00633 
00634 int ff_rewind_with_probe_data(ByteIOContext *s, unsigned char *buf, int buf_size)
00635 {
00636     int64_t buffer_start;
00637     int buffer_size;
00638     int overlap, new_size;
00639 
00640     if (s->write_flag)
00641         return AVERROR(EINVAL);
00642 
00643     buffer_size = s->buf_end - s->buffer;
00644 
00645     /* the buffers must touch or overlap */
00646     if ((buffer_start = s->pos - buffer_size) > buf_size)
00647         return AVERROR(EINVAL);
00648 
00649     overlap = buf_size - buffer_start;
00650     new_size = buf_size + buffer_size - overlap;
00651 
00652     if (new_size > buf_size) {
00653         if (!(buf = av_realloc(buf, new_size)))
00654             return AVERROR(ENOMEM);
00655 
00656         memcpy(buf + buf_size, s->buffer + overlap, buffer_size - overlap);
00657         buf_size = new_size;
00658     }
00659 
00660     av_free(s->buffer);
00661     s->buf_ptr = s->buffer = buf;
00662     s->pos = s->buffer_size = buf_size;
00663     s->buf_end = s->buf_ptr + buf_size;
00664     s->eof_reached = 0;
00665     s->must_flush = 0;
00666 
00667     return 0;
00668 }
00669 
00670 int url_fopen(ByteIOContext **s, const char *filename, int flags)
00671 {
00672     URLContext *h;
00673     int err;
00674 
00675     err = url_open(&h, filename, flags);
00676     if (err < 0)
00677         return err;
00678     err = url_fdopen(s, h);
00679     if (err < 0) {
00680         url_close(h);
00681         return err;
00682     }
00683     return 0;
00684 }
00685 
00686 int url_fclose(ByteIOContext *s)
00687 {
00688     URLContext *h = s->opaque;
00689 
00690     av_free(s->buffer);
00691     av_free(s);
00692     return url_close(h);
00693 }
00694 
00695 URLContext *url_fileno(ByteIOContext *s)
00696 {
00697     return s->opaque;
00698 }
00699 
00700 #if CONFIG_MUXERS
00701 int url_fprintf(ByteIOContext *s, const char *fmt, ...)
00702 {
00703     va_list ap;
00704     char buf[4096];
00705     int ret;
00706 
00707     va_start(ap, fmt);
00708     ret = vsnprintf(buf, sizeof(buf), fmt, ap);
00709     va_end(ap);
00710     put_buffer(s, buf, strlen(buf));
00711     return ret;
00712 }
00713 #endif //CONFIG_MUXERS
00714 
00715 char *url_fgets(ByteIOContext *s, char *buf, int buf_size)
00716 {
00717     int c;
00718     char *q;
00719 
00720     c = url_fgetc(s);
00721     if (c == EOF)
00722         return NULL;
00723     q = buf;
00724     for(;;) {
00725         if (c == EOF || c == '\n')
00726             break;
00727         if ((q - buf) < buf_size - 1)
00728             *q++ = c;
00729         c = url_fgetc(s);
00730     }
00731     if (buf_size > 0)
00732         *q = '\0';
00733     return buf;
00734 }
00735 
00736 int url_fget_max_packet_size(ByteIOContext *s)
00737 {
00738     return s->max_packet_size;
00739 }
00740 
00741 int av_url_read_fpause(ByteIOContext *s, int pause)
00742 {
00743     if (!s->read_pause)
00744         return AVERROR(ENOSYS);
00745     return s->read_pause(s->opaque, pause);
00746 }
00747 
00748 int64_t av_url_read_fseek(ByteIOContext *s, int stream_index,
00749                           int64_t timestamp, int flags)
00750 {
00751     URLContext *h = s->opaque;
00752     int64_t ret;
00753     if (!s->read_seek)
00754         return AVERROR(ENOSYS);
00755     ret = s->read_seek(h, stream_index, timestamp, flags);
00756     if(ret >= 0) {
00757         int64_t pos;
00758         s->buf_ptr = s->buf_end; // Flush buffer
00759         pos = s->seek(h, 0, SEEK_CUR);
00760         if (pos >= 0)
00761             s->pos = pos;
00762         else if (pos != AVERROR(ENOSYS))
00763             ret = pos;
00764     }
00765     return ret;
00766 }
00767 
00768 /* url_open_dyn_buf and url_close_dyn_buf are used in rtp.c to send a response
00769  * back to the server even if CONFIG_MUXERS is false. */
00770 #if CONFIG_MUXERS || CONFIG_NETWORK
00771 /* buffer handling */
00772 int url_open_buf(ByteIOContext **s, uint8_t *buf, int buf_size, int flags)
00773 {
00774     int ret;
00775     *s = av_mallocz(sizeof(ByteIOContext));
00776     if(!*s)
00777         return AVERROR(ENOMEM);
00778     ret = init_put_byte(*s, buf, buf_size,
00779                         (flags & URL_WRONLY || flags & URL_RDWR),
00780                         NULL, NULL, NULL, NULL);
00781     if(ret != 0)
00782         av_freep(s);
00783     return ret;
00784 }
00785 
00786 int url_close_buf(ByteIOContext *s)
00787 {
00788     put_flush_packet(s);
00789     return s->buf_ptr - s->buffer;
00790 }
00791 
00792 /* output in a dynamic buffer */
00793 
00794 typedef struct DynBuffer {
00795     int pos, size, allocated_size;
00796     uint8_t *buffer;
00797     int io_buffer_size;
00798     uint8_t io_buffer[1];
00799 } DynBuffer;
00800 
00801 static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size)
00802 {
00803     DynBuffer *d = opaque;
00804     unsigned new_size, new_allocated_size;
00805 
00806     /* reallocate buffer if needed */
00807     new_size = d->pos + buf_size;
00808     new_allocated_size = d->allocated_size;
00809     if(new_size < d->pos || new_size > INT_MAX/2)
00810         return -1;
00811     while (new_size > new_allocated_size) {
00812         if (!new_allocated_size)
00813             new_allocated_size = new_size;
00814         else
00815             new_allocated_size += new_allocated_size / 2 + 1;
00816     }
00817 
00818     if (new_allocated_size > d->allocated_size) {
00819         d->buffer = av_realloc(d->buffer, new_allocated_size);
00820         if(d->buffer == NULL)
00821              return AVERROR(ENOMEM);
00822         d->allocated_size = new_allocated_size;
00823     }
00824     memcpy(d->buffer + d->pos, buf, buf_size);
00825     d->pos = new_size;
00826     if (d->pos > d->size)
00827         d->size = d->pos;
00828     return buf_size;
00829 }
00830 
00831 static int dyn_packet_buf_write(void *opaque, uint8_t *buf, int buf_size)
00832 {
00833     unsigned char buf1[4];
00834     int ret;
00835 
00836     /* packetized write: output the header */
00837     AV_WB32(buf1, buf_size);
00838     ret= dyn_buf_write(opaque, buf1, 4);
00839     if(ret < 0)
00840         return ret;
00841 
00842     /* then the data */
00843     return dyn_buf_write(opaque, buf, buf_size);
00844 }
00845 
00846 static int64_t dyn_buf_seek(void *opaque, int64_t offset, int whence)
00847 {
00848     DynBuffer *d = opaque;
00849 
00850     if (whence == SEEK_CUR)
00851         offset += d->pos;
00852     else if (whence == SEEK_END)
00853         offset += d->size;
00854     if (offset < 0 || offset > 0x7fffffffLL)
00855         return -1;
00856     d->pos = offset;
00857     return 0;
00858 }
00859 
00860 static int url_open_dyn_buf_internal(ByteIOContext **s, int max_packet_size)
00861 {
00862     DynBuffer *d;
00863     int ret;
00864     unsigned io_buffer_size = max_packet_size ? max_packet_size : 1024;
00865 
00866     if(sizeof(DynBuffer) + io_buffer_size < io_buffer_size)
00867         return -1;
00868     d = av_mallocz(sizeof(DynBuffer) + io_buffer_size);
00869     if (!d)
00870         return AVERROR(ENOMEM);
00871     *s = av_mallocz(sizeof(ByteIOContext));
00872     if(!*s) {
00873         av_free(d);
00874         return AVERROR(ENOMEM);
00875     }
00876     d->io_buffer_size = io_buffer_size;
00877     ret = init_put_byte(*s, d->io_buffer, io_buffer_size,
00878                         1, d, NULL,
00879                         max_packet_size ? dyn_packet_buf_write : dyn_buf_write,
00880                         max_packet_size ? NULL : dyn_buf_seek);
00881     if (ret == 0) {
00882         (*s)->max_packet_size = max_packet_size;
00883     } else {
00884         av_free(d);
00885         av_freep(s);
00886     }
00887     return ret;
00888 }
00889 
00890 int url_open_dyn_buf(ByteIOContext **s)
00891 {
00892     return url_open_dyn_buf_internal(s, 0);
00893 }
00894 
00895 int url_open_dyn_packet_buf(ByteIOContext **s, int max_packet_size)
00896 {
00897     if (max_packet_size <= 0)
00898         return -1;
00899     return url_open_dyn_buf_internal(s, max_packet_size);
00900 }
00901 
00902 int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer)
00903 {
00904     DynBuffer *d = s->opaque;
00905     int size;
00906 
00907     put_flush_packet(s);
00908 
00909     *pbuffer = d->buffer;
00910     size = d->size;
00911     av_free(d);
00912     av_free(s);
00913     return size;
00914 }
00915 #endif /* CONFIG_MUXERS || CONFIG_NETWORK */