]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavformat/aviobuf.c
Use O_DIRECT buffer flushing only when we operate really on O_DIRECT file
[frescor/ffmpeg.git] / libavformat / aviobuf.c
1 /*
2  * Buffered I/O for ffmpeg system
3  * Copyright (c) 2000,2001 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "libavutil/crc.h"
23 #include "libavutil/intreadwrite.h"
24 #include "avformat.h"
25 #include "avio.h"
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <malloc.h>
29
30 #define IO_BUFFER_SIZE 32768
31
32 static void fill_buffer(ByteIOContext *s);
33
34 int init_put_byte(ByteIOContext *s,
35                   unsigned char *buffer,
36                   int buffer_size,
37                   int write_flag,
38                   void *opaque,
39                   int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
40                   int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
41                   int64_t (*seek)(void *opaque, int64_t offset, int whence))
42 {
43     s->buffer = buffer;
44     s->buffer_size = buffer_size;
45     s->buf_ptr = buffer;
46     s->opaque = opaque;
47     url_resetbuf(s, write_flag ? URL_WRONLY : URL_RDONLY);
48     s->write_packet = write_packet;
49     s->read_packet = read_packet;
50     s->seek = seek;
51     s->pos = 0;
52     s->must_flush = 0;
53     s->eof_reached = 0;
54     s->error = 0;
55     s->is_streamed = 0;
56     s->max_packet_size = 0;
57     s->update_checksum= NULL;
58     if(!read_packet && !write_flag){
59         s->pos = buffer_size;
60         s->buf_end = s->buffer + buffer_size;
61     }
62     s->read_pause = NULL;
63     s->read_seek  = NULL;
64     return 0;
65 }
66
67 ByteIOContext *av_alloc_put_byte(
68                   unsigned char *buffer,
69                   int buffer_size,
70                   int write_flag,
71                   void *opaque,
72                   int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
73                   int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
74                   int64_t (*seek)(void *opaque, int64_t offset, int whence))
75 {
76     ByteIOContext *s = av_mallocz(sizeof(ByteIOContext));
77     init_put_byte(s, buffer, buffer_size, write_flag, opaque,
78                   read_packet, write_packet, seek);
79     return s;
80 }
81
82 #define BLOCK_SIZE 512
83
84 static void flush_buffer_o_direct(ByteIOContext *s)
85 {
86     size_t data_len = s->buf_ptr - s->buffer;
87
88     /* Write all the data in the buffer to the disk together with any
89      * additional space at the end of the buffer up to the first
90      * multiple of BLOCK_SIZE. The last block is always written to the
91      * disk despite not being fully filled. If the last block is not
92      * fully filled, we keep it (moved to the begginig of the buffer)
93      * and any subsequent call to this function will rewrite the block
94      * together with the additional data added to the buffer. */
95     size_t to_write = (data_len + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
96     size_t whole_blocks = data_len & ~(BLOCK_SIZE - 1);
97     int64_t res = AVERROR(EPIPE);
98     //av_log(NULL, AV_LOG_ERROR, "%p: YYY dl=%zd, tw=%zd\n", s, data_len, to_write);
99     if (data_len > 0) {
100         if (s->write_packet && !s->error){
101             int ret= s->write_packet(s->opaque, s->buffer, to_write);
102             if(ret < 0){
103                 s->error = ret;
104             }
105         }
106         if(s->update_checksum){
107             av_log(NULL, AV_LOG_ERROR, "Checksumming not implemented in O_DIRECT patch\n");
108             s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
109             s->checksum_ptr= s->buffer;
110         }
111         s->pos += whole_blocks;
112         memcpy(s->buffer, &s->buffer[whole_blocks], data_len - whole_blocks);
113         s->buf_ptr -= whole_blocks;
114
115         if (s->seek)
116             res = s->seek(s->opaque, s->pos, SEEK_SET);
117         if (res < 0)
118             av_log(NULL, AV_LOG_ERROR, "seek error inside flush_buffer: %lld\n", res);
119         //av_log(NULL, AV_LOG_ERROR, "ZZZ tw=%zu, pos=%zd\n", to_write, s->pos);
120     }
121 }
122
123 static void flush_buffer(ByteIOContext *s)
124 {
125     if (s->o_direct_flag) {
126         flush_buffer_o_direct(s);
127         return;
128     }
129     if (s->buf_ptr > s->buffer) {
130         if (s->write_packet && !s->error){
131             int ret= s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer);
132             if(ret < 0){
133                 s->error = ret;
134             }
135         }
136         if(s->update_checksum){
137             s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
138             s->checksum_ptr= s->buffer;
139         }
140         s->pos += s->buf_ptr - s->buffer;
141     }
142     s->buf_ptr = s->buffer;
143 }
144
145 void put_byte(ByteIOContext *s, int b)
146 {
147     *(s->buf_ptr)++ = b;
148     if (s->buf_ptr >= s->buf_end)
149         flush_buffer(s);
150 }
151
152 void put_buffer(ByteIOContext *s, const unsigned char *buf, int size)
153 {
154     int len;
155
156     while (size > 0) {
157         len = (s->buf_end - s->buf_ptr);
158         if (len > size)
159             len = size;
160         memcpy(s->buf_ptr, buf, len);
161         s->buf_ptr += len;
162
163         if (s->buf_ptr >= s->buf_end)
164             flush_buffer(s);
165
166         buf += len;
167         size -= len;
168     }
169 }
170
171 void put_flush_packet(ByteIOContext *s)
172 {
173     flush_buffer(s);
174     s->must_flush = 0;
175 }
176
177 int64_t url_fseek(ByteIOContext *s, int64_t offset, int whence)
178 {
179     int64_t offset1;
180     int64_t pos;
181
182     if(!s)
183         return AVERROR(EINVAL);
184
185     pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer));
186
187     if (whence != SEEK_CUR && whence != SEEK_SET)
188         return AVERROR(EINVAL);
189
190     if (whence == SEEK_CUR) {
191         offset1 = pos + (s->buf_ptr - s->buffer);
192         if (offset == 0)
193             return offset1;
194         offset += offset1;
195     }
196     av_log(NULL, AV_LOG_ERROR, "%p: SEEK from %llu to %llu\n", s, pos, offset);
197
198     offset1 = offset - pos;
199     if (!s->must_flush &&
200         offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) {
201         /* can do the seek inside the buffer */
202         s->buf_ptr = s->buffer + offset1;
203         av_log(NULL, AV_LOG_ERROR, "Internal seek by %llu\n", offset1);
204     } else if(s->is_streamed && !s->write_flag &&
205               offset1 >= 0 && offset1 < (s->buf_end - s->buffer) + (1<<16)){
206         while(s->pos < offset && !s->eof_reached)
207             fill_buffer(s);
208         if (s->eof_reached)
209             return AVERROR(EPIPE);
210         s->buf_ptr = s->buf_end + offset - s->pos;
211     } else {
212         int64_t res = AVERROR(EPIPE);
213
214 #if CONFIG_MUXERS || CONFIG_NETWORK
215         if (s->write_flag) {
216             flush_buffer(s);
217             s->must_flush = 1;
218         }
219 #endif /* CONFIG_MUXERS || CONFIG_NETWORK */
220 #warning TODO read the whole block from the file to the buffer
221         if (!s->seek || (res = s->seek(s->opaque, offset, SEEK_SET)) < 0)
222             return res;
223         if (!s->write_flag)
224             s->buf_end = s->buffer;
225         s->buf_ptr = s->buffer;
226         s->pos = offset;
227     }
228     s->eof_reached = 0;
229     return offset;
230 }
231
232 void url_fskip(ByteIOContext *s, int64_t offset)
233 {
234     url_fseek(s, offset, SEEK_CUR);
235 }
236
237 int64_t url_ftell(ByteIOContext *s)
238 {
239     return url_fseek(s, 0, SEEK_CUR);
240 }
241
242 int64_t url_fsize(ByteIOContext *s)
243 {
244     int64_t size;
245
246     if(!s)
247         return AVERROR(EINVAL);
248
249     if (!s->seek)
250         return AVERROR(EPIPE);
251     size = s->seek(s->opaque, 0, AVSEEK_SIZE);
252     if(size<0){
253         if ((size = s->seek(s->opaque, -1, SEEK_END)) < 0)
254             return size;
255         size++;
256         s->seek(s->opaque, s->pos, SEEK_SET);
257     }
258     return size;
259 }
260
261 int url_feof(ByteIOContext *s)
262 {
263     if(!s)
264         return 0;
265     return s->eof_reached;
266 }
267
268 int url_ferror(ByteIOContext *s)
269 {
270     if(!s)
271         return 0;
272     return s->error;
273 }
274
275 void put_le32(ByteIOContext *s, unsigned int val)
276 {
277     put_byte(s, val);
278     put_byte(s, val >> 8);
279     put_byte(s, val >> 16);
280     put_byte(s, val >> 24);
281 }
282
283 void put_be32(ByteIOContext *s, unsigned int val)
284 {
285     put_byte(s, val >> 24);
286     put_byte(s, val >> 16);
287     put_byte(s, val >> 8);
288     put_byte(s, val);
289 }
290
291 void put_strz(ByteIOContext *s, const char *str)
292 {
293     if (str)
294         put_buffer(s, (const unsigned char *) str, strlen(str) + 1);
295     else
296         put_byte(s, 0);
297 }
298
299 void put_le64(ByteIOContext *s, uint64_t val)
300 {
301     put_le32(s, (uint32_t)(val & 0xffffffff));
302     put_le32(s, (uint32_t)(val >> 32));
303 }
304
305 void put_be64(ByteIOContext *s, uint64_t val)
306 {
307     put_be32(s, (uint32_t)(val >> 32));
308     put_be32(s, (uint32_t)(val & 0xffffffff));
309 }
310
311 void put_le16(ByteIOContext *s, unsigned int val)
312 {
313     put_byte(s, val);
314     put_byte(s, val >> 8);
315 }
316
317 void put_be16(ByteIOContext *s, unsigned int val)
318 {
319     put_byte(s, val >> 8);
320     put_byte(s, val);
321 }
322
323 void put_le24(ByteIOContext *s, unsigned int val)
324 {
325     put_le16(s, val & 0xffff);
326     put_byte(s, val >> 16);
327 }
328
329 void put_be24(ByteIOContext *s, unsigned int val)
330 {
331     put_be16(s, val >> 8);
332     put_byte(s, val);
333 }
334
335 void put_tag(ByteIOContext *s, const char *tag)
336 {
337     while (*tag) {
338         put_byte(s, *tag++);
339     }
340 }
341
342 /* Input stream */
343
344 static void fill_buffer(ByteIOContext *s)
345 {
346     uint8_t *dst= !s->max_packet_size && s->buf_end - s->buffer < s->buffer_size ? s->buf_ptr : s->buffer;
347     int len= s->buffer_size - (dst - s->buffer);
348
349     assert(s->buf_ptr == s->buf_end);
350
351     /* no need to do anything if EOF already reached */
352     if (s->eof_reached)
353         return;
354
355     if(s->update_checksum && dst == s->buffer){
356         if(s->buf_end > s->checksum_ptr)
357             s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_end - s->checksum_ptr);
358         s->checksum_ptr= s->buffer;
359     }
360
361     if(s->read_packet)
362         len = s->read_packet(s->opaque, dst, len);
363     else
364         len = 0;
365     if (len <= 0) {
366         /* do not modify buffer if EOF reached so that a seek back can
367            be done without rereading data */
368         s->eof_reached = 1;
369         if(len<0)
370             s->error= len;
371     } else {
372         s->pos += len;
373         s->buf_ptr = dst;
374         s->buf_end = dst + len;
375     }
376 }
377
378 unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf,
379                                     unsigned int len)
380 {
381     return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf, len);
382 }
383
384 unsigned long get_checksum(ByteIOContext *s)
385 {
386     s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
387     s->update_checksum= NULL;
388     return s->checksum;
389 }
390
391 void init_checksum(ByteIOContext *s,
392                    unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len),
393                    unsigned long checksum)
394 {
395     s->update_checksum= update_checksum;
396     if(s->update_checksum){
397         s->checksum= checksum;
398         s->checksum_ptr= s->buf_ptr;
399     }
400 }
401
402 /* XXX: put an inline version */
403 int get_byte(ByteIOContext *s)
404 {
405     if (s->buf_ptr < s->buf_end) {
406         return *s->buf_ptr++;
407     } else {
408         fill_buffer(s);
409         if (s->buf_ptr < s->buf_end)
410             return *s->buf_ptr++;
411         else
412             return 0;
413     }
414 }
415
416 int url_fgetc(ByteIOContext *s)
417 {
418     if (s->buf_ptr < s->buf_end) {
419         return *s->buf_ptr++;
420     } else {
421         fill_buffer(s);
422         if (s->buf_ptr < s->buf_end)
423             return *s->buf_ptr++;
424         else
425             return URL_EOF;
426     }
427 }
428
429 int get_buffer(ByteIOContext *s, unsigned char *buf, int size)
430 {
431     int len, size1;
432
433     size1 = size;
434     while (size > 0) {
435         len = s->buf_end - s->buf_ptr;
436         if (len > size)
437             len = size;
438         if (len == 0) {
439             if(size > s->buffer_size && !s->update_checksum){
440                 if(s->read_packet)
441                     len = s->read_packet(s->opaque, buf, size);
442                 if (len <= 0) {
443                     /* do not modify buffer if EOF reached so that a seek back can
444                     be done without rereading data */
445                     s->eof_reached = 1;
446                     if(len<0)
447                         s->error= len;
448                     break;
449                 } else {
450                     s->pos += len;
451                     size -= len;
452                     buf += len;
453                     s->buf_ptr = s->buffer;
454                     s->buf_end = s->buffer/* + len*/;
455                 }
456             }else{
457                 fill_buffer(s);
458                 len = s->buf_end - s->buf_ptr;
459                 if (len == 0)
460                     break;
461             }
462         } else {
463             memcpy(buf, s->buf_ptr, len);
464             buf += len;
465             s->buf_ptr += len;
466             size -= len;
467         }
468     }
469     return size1 - size;
470 }
471
472 int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size)
473 {
474     int len;
475
476     if(size<0)
477         return -1;
478
479     len = s->buf_end - s->buf_ptr;
480     if (len == 0) {
481         fill_buffer(s);
482         len = s->buf_end - s->buf_ptr;
483     }
484     if (len > size)
485         len = size;
486     memcpy(buf, s->buf_ptr, len);
487     s->buf_ptr += len;
488     return len;
489 }
490
491 unsigned int get_le16(ByteIOContext *s)
492 {
493     unsigned int val;
494     val = get_byte(s);
495     val |= get_byte(s) << 8;
496     return val;
497 }
498
499 unsigned int get_le24(ByteIOContext *s)
500 {
501     unsigned int val;
502     val = get_le16(s);
503     val |= get_byte(s) << 16;
504     return val;
505 }
506
507 unsigned int get_le32(ByteIOContext *s)
508 {
509     unsigned int val;
510     val = get_le16(s);
511     val |= get_le16(s) << 16;
512     return val;
513 }
514
515 uint64_t get_le64(ByteIOContext *s)
516 {
517     uint64_t val;
518     val = (uint64_t)get_le32(s);
519     val |= (uint64_t)get_le32(s) << 32;
520     return val;
521 }
522
523 unsigned int get_be16(ByteIOContext *s)
524 {
525     unsigned int val;
526     val = get_byte(s) << 8;
527     val |= get_byte(s);
528     return val;
529 }
530
531 unsigned int get_be24(ByteIOContext *s)
532 {
533     unsigned int val;
534     val = get_be16(s) << 8;
535     val |= get_byte(s);
536     return val;
537 }
538 unsigned int get_be32(ByteIOContext *s)
539 {
540     unsigned int val;
541     val = get_be16(s) << 16;
542     val |= get_be16(s);
543     return val;
544 }
545
546 char *get_strz(ByteIOContext *s, char *buf, int maxlen)
547 {
548     int i = 0;
549     char c;
550
551     while ((c = get_byte(s))) {
552         if (i < maxlen-1)
553             buf[i++] = c;
554     }
555
556     buf[i] = 0; /* Ensure null terminated, but may be truncated */
557
558     return buf;
559 }
560
561 uint64_t get_be64(ByteIOContext *s)
562 {
563     uint64_t val;
564     val = (uint64_t)get_be32(s) << 32;
565     val |= (uint64_t)get_be32(s);
566     return val;
567 }
568
569 uint64_t ff_get_v(ByteIOContext *bc){
570     uint64_t val = 0;
571     int tmp;
572
573     do{
574         tmp = get_byte(bc);
575         val= (val<<7) + (tmp&127);
576     }while(tmp&128);
577     return val;
578 }
579
580 int url_fdopen(ByteIOContext **s, URLContext *h)
581 {
582     uint8_t *buffer;
583     int buffer_size, max_packet_size;
584
585
586     max_packet_size = url_get_max_packet_size(h);
587     if (max_packet_size) {
588         buffer_size = max_packet_size; /* no need to bufferize more than one packet */
589     } else {
590         buffer_size = IO_BUFFER_SIZE;
591     }
592     (*s)->o_direct_flag = !!(h->flags & URL_DIRECT);
593     if ((*s)->o_direct_flag) {
594         buffer_size = 2*buffer_size+BLOCK_SIZE;
595         buffer = memalign(sysconf(_SC_PAGESIZE), buffer_size);
596         ;
597     } else {
598         buffer = av_malloc(buffer_size);
599     }
600     if (!buffer)
601         return AVERROR(ENOMEM);
602
603     *s = av_mallocz(sizeof(ByteIOContext));
604     if(!*s) {
605         av_free(buffer);
606         return AVERROR(ENOMEM);
607     }
608
609     if (init_put_byte(*s, buffer, buffer_size,
610                       (h->flags & URL_WRONLY || h->flags & URL_RDWR), h,
611                       url_read, url_write, url_seek) < 0) {
612         av_free(buffer);
613         av_freep(s);
614         return AVERROR(EIO);
615     }
616     (*s)->is_streamed = h->is_streamed;
617     (*s)->max_packet_size = max_packet_size;
618     if(h->prot) {
619         (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause;
620         (*s)->read_seek  = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek;
621     }
622     return 0;
623 }
624
625 int url_setbufsize(ByteIOContext *s, int buf_size)
626 {
627     uint8_t *buffer;
628     buffer = av_malloc(buf_size);
629     if (!buffer)
630         return AVERROR(ENOMEM);
631
632     av_free(s->buffer);
633     s->buffer = buffer;
634     s->buffer_size = buf_size;
635     s->buf_ptr = buffer;
636     url_resetbuf(s, s->write_flag ? URL_WRONLY : URL_RDONLY);
637     return 0;
638 }
639
640 int url_resetbuf(ByteIOContext *s, int flags)
641 {
642     URLContext *h = s->opaque;
643     if ((flags & URL_RDWR) || (h && h->flags != flags && !h->flags & URL_RDWR))
644         return AVERROR(EINVAL);
645
646     if (flags & URL_WRONLY) {
647         s->buf_end = s->buffer + s->buffer_size;
648         s->write_flag = 1;
649     } else {
650         s->buf_end = s->buffer;
651         s->write_flag = 0;
652     }
653     return 0;
654 }
655
656 int url_fopen(ByteIOContext **s, const char *filename, int flags)
657 {
658     URLContext *h;
659     int err;
660
661     err = url_open(&h, filename, flags);
662     if (err < 0)
663         return err;
664     err = url_fdopen(s, h);
665     if (err < 0) {
666         url_close(h);
667         return err;
668     }
669     return 0;
670 }
671
672 int url_fclose(ByteIOContext *s)
673 {
674     URLContext *h = s->opaque;
675
676     av_free(s->buffer);
677     av_free(s);
678     return url_close(h);
679 }
680
681 URLContext *url_fileno(ByteIOContext *s)
682 {
683     return s->opaque;
684 }
685
686 #if CONFIG_MUXERS
687 int url_fprintf(ByteIOContext *s, const char *fmt, ...)
688 {
689     va_list ap;
690     char buf[4096];
691     int ret;
692
693     va_start(ap, fmt);
694     ret = vsnprintf(buf, sizeof(buf), fmt, ap);
695     va_end(ap);
696     put_buffer(s, buf, strlen(buf));
697     return ret;
698 }
699 #endif //CONFIG_MUXERS
700
701 char *url_fgets(ByteIOContext *s, char *buf, int buf_size)
702 {
703     int c;
704     char *q;
705
706     c = url_fgetc(s);
707     if (c == EOF)
708         return NULL;
709     q = buf;
710     for(;;) {
711         if (c == EOF || c == '\n')
712             break;
713         if ((q - buf) < buf_size - 1)
714             *q++ = c;
715         c = url_fgetc(s);
716     }
717     if (buf_size > 0)
718         *q = '\0';
719     return buf;
720 }
721
722 int url_fget_max_packet_size(ByteIOContext *s)
723 {
724     return s->max_packet_size;
725 }
726
727 int av_url_read_fpause(ByteIOContext *s, int pause)
728 {
729     if (!s->read_pause)
730         return AVERROR(ENOSYS);
731     return s->read_pause(s->opaque, pause);
732 }
733
734 int64_t av_url_read_fseek(ByteIOContext *s, int stream_index,
735                           int64_t timestamp, int flags)
736 {
737     URLContext *h = s->opaque;
738     int64_t ret;
739     if (!s->read_seek)
740         return AVERROR(ENOSYS);
741     ret = s->read_seek(h, stream_index, timestamp, flags);
742     if(ret >= 0) {
743         s->buf_ptr = s->buf_end; // Flush buffer
744         s->pos = s->seek(h, 0, SEEK_CUR);
745     }
746     return ret;
747 }
748
749 /* url_open_dyn_buf and url_close_dyn_buf are used in rtp.c to send a response
750  * back to the server even if CONFIG_MUXERS is false. */
751 #if CONFIG_MUXERS || CONFIG_NETWORK
752 /* buffer handling */
753 int url_open_buf(ByteIOContext **s, uint8_t *buf, int buf_size, int flags)
754 {
755     int ret;
756     *s = av_mallocz(sizeof(ByteIOContext));
757     if(!*s)
758         return AVERROR(ENOMEM);
759     ret = init_put_byte(*s, buf, buf_size,
760                         (flags & URL_WRONLY || flags & URL_RDWR),
761                         NULL, NULL, NULL, NULL);
762     if(ret != 0)
763         av_freep(s);
764     return ret;
765 }
766
767 int url_close_buf(ByteIOContext *s)
768 {
769     put_flush_packet(s);
770     return s->buf_ptr - s->buffer;
771 }
772
773 /* output in a dynamic buffer */
774
775 typedef struct DynBuffer {
776     int pos, size, allocated_size;
777     uint8_t *buffer;
778     int io_buffer_size;
779     uint8_t io_buffer[1];
780 } DynBuffer;
781
782 static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size)
783 {
784     DynBuffer *d = opaque;
785     unsigned new_size, new_allocated_size;
786
787     /* reallocate buffer if needed */
788     new_size = d->pos + buf_size;
789     new_allocated_size = d->allocated_size;
790     if(new_size < d->pos || new_size > INT_MAX/2)
791         return -1;
792     while (new_size > new_allocated_size) {
793         if (!new_allocated_size)
794             new_allocated_size = new_size;
795         else
796             new_allocated_size += new_allocated_size / 2 + 1;
797     }
798
799     if (new_allocated_size > d->allocated_size) {
800         d->buffer = av_realloc(d->buffer, new_allocated_size);
801         if(d->buffer == NULL)
802              return AVERROR(ENOMEM);
803         d->allocated_size = new_allocated_size;
804     }
805     memcpy(d->buffer + d->pos, buf, buf_size);
806     d->pos = new_size;
807     if (d->pos > d->size)
808         d->size = d->pos;
809     return buf_size;
810 }
811
812 static int dyn_packet_buf_write(void *opaque, uint8_t *buf, int buf_size)
813 {
814     unsigned char buf1[4];
815     int ret;
816
817     /* packetized write: output the header */
818     AV_WB32(buf1, buf_size);
819     ret= dyn_buf_write(opaque, buf1, 4);
820     if(ret < 0)
821         return ret;
822
823     /* then the data */
824     return dyn_buf_write(opaque, buf, buf_size);
825 }
826
827 static int64_t dyn_buf_seek(void *opaque, int64_t offset, int whence)
828 {
829     DynBuffer *d = opaque;
830
831     if (whence == SEEK_CUR)
832         offset += d->pos;
833     else if (whence == SEEK_END)
834         offset += d->size;
835     if (offset < 0 || offset > 0x7fffffffLL)
836         return -1;
837     d->pos = offset;
838     return 0;
839 }
840
841 static int url_open_dyn_buf_internal(ByteIOContext **s, int max_packet_size)
842 {
843     DynBuffer *d;
844     int ret;
845     unsigned io_buffer_size = max_packet_size ? max_packet_size : 1024;
846
847     if(sizeof(DynBuffer) + io_buffer_size < io_buffer_size)
848         return -1;
849     d = av_mallocz(sizeof(DynBuffer) + io_buffer_size);
850     if (!d)
851         return AVERROR(ENOMEM);
852     *s = av_mallocz(sizeof(ByteIOContext));
853     if(!*s) {
854         av_free(d);
855         return AVERROR(ENOMEM);
856     }
857     d->io_buffer_size = io_buffer_size;
858     ret = init_put_byte(*s, d->io_buffer, io_buffer_size,
859                         1, d, NULL,
860                         max_packet_size ? dyn_packet_buf_write : dyn_buf_write,
861                         max_packet_size ? NULL : dyn_buf_seek);
862     if (ret == 0) {
863         (*s)->max_packet_size = max_packet_size;
864     } else {
865         av_free(d);
866         av_freep(s);
867     }
868     return ret;
869 }
870
871 int url_open_dyn_buf(ByteIOContext **s)
872 {
873     return url_open_dyn_buf_internal(s, 0);
874 }
875
876 int url_open_dyn_packet_buf(ByteIOContext **s, int max_packet_size)
877 {
878     if (max_packet_size <= 0)
879         return -1;
880     return url_open_dyn_buf_internal(s, max_packet_size);
881 }
882
883 int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer)
884 {
885     DynBuffer *d = s->opaque;
886     int size;
887
888     put_flush_packet(s);
889
890     *pbuffer = d->buffer;
891     size = d->size;
892     av_free(d);
893     av_free(s);
894     return size;
895 }
896 #endif /* CONFIG_MUXERS || CONFIG_NETWORK */