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