source: trunk/libavformat/aviobuf.c@ 259

Last change on this file since 259 was 259, checked in by vladest, 18 years ago

libavcodec update
Clicking on audio volume shaft was not changed volume. fixed

File size: 19.4 KB
Line 
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#include "avformat.h"
22#include "avio.h"
23#include <stdarg.h>
24
25#define IO_BUFFER_SIZE 32768
26
27static void fill_buffer(ByteIOContext *s);
28
29int init_put_byte(ByteIOContext *s,
30 unsigned char *buffer,
31 int buffer_size,
32 int write_flag,
33 void *opaque,
34 int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
35 int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
36 offset_t (*seek)(void *opaque, offset_t offset, int whence))
37{
38 s->buffer = buffer;
39 s->buffer_size = buffer_size;
40 s->buf_ptr = buffer;
41 s->write_flag = write_flag;
42 if (!s->write_flag)
43 s->buf_end = buffer;
44 else
45 s->buf_end = buffer + buffer_size;
46 s->opaque = opaque;
47 s->write_packet = write_packet;
48 s->read_packet = read_packet;
49 s->seek = seek;
50 s->pos = 0;
51 s->must_flush = 0;
52 s->eof_reached = 0;
53 s->error = 0;
54 s->is_streamed = 0;
55 s->max_packet_size = 0;
56 s->update_checksum= NULL;
57 if(!read_packet && !write_flag){
58 s->pos = buffer_size;
59 s->buf_end = s->buffer + buffer_size;
60 }
61 return 0;
62}
63
64static void flush_buffer(ByteIOContext *s)
65{
66 if (s->buf_ptr > s->buffer) {
67 if (s->write_packet && !s->error){
68 int ret= s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer);
69 if(ret < 0){
70 s->error = ret;
71 }
72 }
73 if(s->update_checksum){
74 s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
75 s->checksum_ptr= s->buffer;
76 }
77 s->pos += s->buf_ptr - s->buffer;
78 }
79 s->buf_ptr = s->buffer;
80}
81
82void put_byte(ByteIOContext *s, int b)
83{
84 *(s->buf_ptr)++ = b;
85 if (s->buf_ptr >= s->buf_end)
86 flush_buffer(s);
87}
88
89void put_buffer(ByteIOContext *s, const unsigned char *buf, int size)
90{
91 int len;
92
93 while (size > 0) {
94 len = (s->buf_end - s->buf_ptr);
95 if (len > size)
96 len = size;
97 memcpy(s->buf_ptr, buf, len);
98 s->buf_ptr += len;
99
100 if (s->buf_ptr >= s->buf_end)
101 flush_buffer(s);
102
103 buf += len;
104 size -= len;
105 }
106}
107
108void put_flush_packet(ByteIOContext *s)
109{
110 flush_buffer(s);
111 s->must_flush = 0;
112}
113
114offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence)
115{
116 offset_t offset1;
117 offset_t pos= s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer));
118
119 if (whence != SEEK_CUR && whence != SEEK_SET)
120 return -EINVAL;
121
122 if (whence == SEEK_CUR) {
123 offset1 = pos + (s->buf_ptr - s->buffer);
124 if (offset == 0)
125 return offset1;
126 offset += offset1;
127 }
128 offset1 = offset - pos;
129 if (!s->must_flush &&
130 offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
131 /* can do the seek inside the buffer */
132 s->buf_ptr = s->buffer + offset1;
133 } else if(s->is_streamed && !s->write_flag &&
134 offset1 >= 0 && offset1 < (s->buf_end - s->buffer) + (1<<16)){
135 while(s->pos < offset && !s->eof_reached)
136 fill_buffer(s);
137 s->buf_ptr = s->buf_end + offset - s->pos;
138 } else {
139#ifdef CONFIG_MUXERS
140 if (s->write_flag) {
141 flush_buffer(s);
142 s->must_flush = 1;
143 } else
144#endif //CONFIG_MUXERS
145 {
146 s->buf_end = s->buffer;
147 }
148 s->buf_ptr = s->buffer;
149 if (!s->seek || s->seek(s->opaque, offset, SEEK_SET) == (offset_t)-EPIPE)
150 return -EPIPE;
151 s->pos = offset;
152 }
153 s->eof_reached = 0;
154 return offset;
155}
156
157void url_fskip(ByteIOContext *s, offset_t offset)
158{
159 url_fseek(s, offset, SEEK_CUR);
160}
161
162offset_t url_ftell(ByteIOContext *s)
163{
164 return url_fseek(s, 0, SEEK_CUR);
165}
166
167offset_t url_fsize(ByteIOContext *s)
168{
169 offset_t size;
170
171 if (!s->seek)
172 return -EPIPE;
173 size = s->seek(s->opaque, -1, SEEK_END) + 1;
174 s->seek(s->opaque, s->pos, SEEK_SET);
175 return size;
176}
177
178int url_feof(ByteIOContext *s)
179{
180 return s->eof_reached;
181}
182
183int url_ferror(ByteIOContext *s)
184{
185 return s->error;
186}
187
188#if defined(CONFIG_MUXERS) || defined(CONFIG_PROTOCOLS)
189void put_le32(ByteIOContext *s, unsigned int val)
190{
191 put_byte(s, val);
192 put_byte(s, val >> 8);
193 put_byte(s, val >> 16);
194 put_byte(s, val >> 24);
195}
196
197void put_be32(ByteIOContext *s, unsigned int val)
198{
199 put_byte(s, val >> 24);
200 put_byte(s, val >> 16);
201 put_byte(s, val >> 8);
202 put_byte(s, val);
203}
204
205void put_strz(ByteIOContext *s, const char *str)
206{
207 if (str)
208 put_buffer(s, (const unsigned char *) str, strlen(str) + 1);
209 else
210 put_byte(s, 0);
211}
212
213void put_le64(ByteIOContext *s, uint64_t val)
214{
215 put_le32(s, (uint32_t)(val & 0xffffffff));
216 put_le32(s, (uint32_t)(val >> 32));
217}
218
219void put_be64(ByteIOContext *s, uint64_t val)
220{
221 put_be32(s, (uint32_t)(val >> 32));
222 put_be32(s, (uint32_t)(val & 0xffffffff));
223}
224
225void put_le16(ByteIOContext *s, unsigned int val)
226{
227 put_byte(s, val);
228 put_byte(s, val >> 8);
229}
230
231void put_be16(ByteIOContext *s, unsigned int val)
232{
233 put_byte(s, val >> 8);
234 put_byte(s, val);
235}
236
237void put_le24(ByteIOContext *s, unsigned int val)
238{
239 put_le16(s, val & 0xffff);
240 put_byte(s, val >> 16);
241}
242
243void put_be24(ByteIOContext *s, unsigned int val)
244{
245 put_be16(s, val >> 8);
246 put_byte(s, val);
247}
248
249void put_tag(ByteIOContext *s, const char *tag)
250{
251 while (*tag) {
252 put_byte(s, *tag++);
253 }
254}
255#endif //CONFIG_MUXERS || CONFIG_PROTOCOLS
256
257/* Input stream */
258
259static void fill_buffer(ByteIOContext *s)
260{
261 int len;
262
263 /* no need to do anything if EOF already reached */
264 if (s->eof_reached)
265 return;
266
267 if(s->update_checksum){
268 if(s->buf_end > s->checksum_ptr)
269 s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_end - s->checksum_ptr);
270 s->checksum_ptr= s->buffer;
271 }
272
273 len = s->read_packet(s->opaque, s->buffer, s->buffer_size);
274 if (len <= 0) {
275 /* do not modify buffer if EOF reached so that a seek back can
276 be done without rereading data */
277 s->eof_reached = 1;
278 if(len<0)
279 s->error= len;
280 } else {
281 s->pos += len;
282 s->buf_ptr = s->buffer;
283 s->buf_end = s->buffer + len;
284 }
285}
286
287unsigned long get_checksum(ByteIOContext *s){
288 s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
289 s->update_checksum= NULL;
290 return s->checksum;
291}
292
293void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum){
294 s->update_checksum= update_checksum;
295 if(s->update_checksum){
296 s->checksum= checksum;
297 s->checksum_ptr= s->buf_ptr;
298 }
299}
300
301/* NOTE: return 0 if EOF, so you cannot use it if EOF handling is
302 necessary */
303/* XXX: put an inline version */
304int get_byte(ByteIOContext *s)
305{
306 if (s->buf_ptr < s->buf_end) {
307 return *s->buf_ptr++;
308 } else {
309 fill_buffer(s);
310 if (s->buf_ptr < s->buf_end)
311 return *s->buf_ptr++;
312 else
313 return 0;
314 }
315}
316
317/* NOTE: return URL_EOF (-1) if EOF */
318int url_fgetc(ByteIOContext *s)
319{
320 if (s->buf_ptr < s->buf_end) {
321 return *s->buf_ptr++;
322 } else {
323 fill_buffer(s);
324 if (s->buf_ptr < s->buf_end)
325 return *s->buf_ptr++;
326 else
327 return URL_EOF;
328 }
329}
330
331int get_buffer(ByteIOContext *s, unsigned char *buf, int size)
332{
333 int len, size1;
334
335 size1 = size;
336 while (size > 0) {
337 len = s->buf_end - s->buf_ptr;
338 if (len > size)
339 len = size;
340 if (len == 0) {
341 if(size > s->buffer_size && !s->update_checksum){
342 len = s->read_packet(s->opaque, buf, size);
343 if (len <= 0) {
344 /* do not modify buffer if EOF reached so that a seek back can
345 be done without rereading data */
346 s->eof_reached = 1;
347 if(len<0)
348 s->error= len;
349 break;
350 } else {
351 s->pos += len;
352 size -= len;
353 buf += len;
354 s->buf_ptr = s->buffer;
355 s->buf_end = s->buffer/* + len*/;
356 }
357 }else{
358 fill_buffer(s);
359 len = s->buf_end - s->buf_ptr;
360 if (len == 0)
361 break;
362 }
363 } else {
364 memcpy(buf, s->buf_ptr, len);
365 buf += len;
366 s->buf_ptr += len;
367 size -= len;
368 }
369 }
370 return size1 - size;
371}
372
373int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size)
374{
375 int len;
376
377 if(size<0)
378 return -1;
379
380 len = s->buf_end - s->buf_ptr;
381 if (len == 0) {
382 fill_buffer(s);
383 len = s->buf_end - s->buf_ptr;
384 }
385 if (len > size)
386 len = size;
387 memcpy(buf, s->buf_ptr, len);
388 s->buf_ptr += len;
389 return len;
390}
391
392unsigned int get_le16(ByteIOContext *s)
393{
394 unsigned int val;
395 val = get_byte(s);
396 val |= get_byte(s) << 8;
397 return val;
398}
399
400unsigned int get_le24(ByteIOContext *s)
401{
402 unsigned int val;
403 val = get_le16(s);
404 val |= get_byte(s) << 16;
405 return val;
406}
407
408unsigned int get_le32(ByteIOContext *s)
409{
410 unsigned int val;
411 val = get_le16(s);
412 val |= get_le16(s) << 16;
413 return val;
414}
415
416uint64_t get_le64(ByteIOContext *s)
417{
418 uint64_t val;
419 val = (uint64_t)get_le32(s);
420 val |= (uint64_t)get_le32(s) << 32;
421 return val;
422}
423
424unsigned int get_be16(ByteIOContext *s)
425{
426 unsigned int val;
427 val = get_byte(s) << 8;
428 val |= get_byte(s);
429 return val;
430}
431
432unsigned int get_be24(ByteIOContext *s)
433{
434 unsigned int val;
435 val = get_be16(s) << 8;
436 val |= get_byte(s);
437 return val;
438}
439unsigned int get_be32(ByteIOContext *s)
440{
441 unsigned int val;
442 val = get_be16(s) << 16;
443 val |= get_be16(s);
444 return val;
445}
446
447char *get_strz(ByteIOContext *s, char *buf, int maxlen)
448{
449 int i = 0;
450 char c;
451
452 while ((c = get_byte(s))) {
453 if (i < maxlen-1)
454 buf[i++] = c;
455 }
456
457 buf[i] = 0; /* Ensure null terminated, but may be truncated */
458
459 return buf;
460}
461
462uint64_t get_be64(ByteIOContext *s)
463{
464 uint64_t val;
465 val = (uint64_t)get_be32(s) << 32;
466 val |= (uint64_t)get_be32(s);
467 return val;
468}
469
470/* link with avio functions */
471
472#ifdef CONFIG_MUXERS
473static int url_write_packet(void *opaque, uint8_t *buf, int buf_size)
474{
475 URLContext *h = opaque;
476 return url_write(h, buf, buf_size);
477}
478#else
479#define url_write_packet NULL
480#endif //CONFIG_MUXERS
481
482static int url_read_packet(void *opaque, uint8_t *buf, int buf_size)
483{
484 URLContext *h = opaque;
485 return url_read(h, buf, buf_size);
486}
487
488static offset_t url_seek_packet(void *opaque, offset_t offset, int whence)
489{
490 URLContext *h = opaque;
491 return url_seek(h, offset, whence);
492 //return 0;
493}
494
495int url_fdopen(ByteIOContext *s, URLContext *h)
496{
497 uint8_t *buffer;
498 int buffer_size, max_packet_size;
499
500
501 max_packet_size = url_get_max_packet_size(h);
502 if (max_packet_size) {
503 buffer_size = max_packet_size; /* no need to bufferize more than one packet */
504 } else {
505 buffer_size = IO_BUFFER_SIZE;
506 }
507 buffer = av_malloc(buffer_size);
508 if (!buffer)
509 return -ENOMEM;
510
511 if (init_put_byte(s, buffer, buffer_size,
512 (h->flags & URL_WRONLY || h->flags & URL_RDWR), h,
513 url_read_packet, url_write_packet, url_seek_packet) < 0) {
514 av_free(buffer);
515 return AVERROR_IO;
516 }
517 s->is_streamed = h->is_streamed;
518 s->max_packet_size = max_packet_size;
519 return 0;
520}
521
522/* XXX: must be called before any I/O */
523int url_setbufsize(ByteIOContext *s, int buf_size)
524{
525 uint8_t *buffer;
526 buffer = av_malloc(buf_size);
527 if (!buffer)
528 return -ENOMEM;
529
530 av_free(s->buffer);
531 s->buffer = buffer;
532 s->buffer_size = buf_size;
533 s->buf_ptr = buffer;
534 if (!s->write_flag)
535 s->buf_end = buffer;
536 else
537 s->buf_end = buffer + buf_size;
538 return 0;
539}
540
541/* NOTE: when opened as read/write, the buffers are only used for
542 reading */
543int url_fopen(ByteIOContext *s, const char *filename, int flags)
544{
545 URLContext *h;
546 int err;
547
548 err = url_open(&h, filename, flags);
549 if (err < 0)
550 return err;
551 err = url_fdopen(s, h);
552 if (err < 0) {
553 url_close(h);
554 return err;
555 }
556 return 0;
557}
558
559int url_fclose(ByteIOContext *s)
560{
561 URLContext *h = s->opaque;
562
563 av_free(s->buffer);
564 memset(s, 0, sizeof(ByteIOContext));
565 return url_close(h);
566}
567
568URLContext *url_fileno(ByteIOContext *s)
569{
570 return s->opaque;
571}
572
573#ifdef CONFIG_MUXERS
574/* XXX: currently size is limited */
575int url_fprintf(ByteIOContext *s, const char *fmt, ...)
576{
577 va_list ap;
578 char buf[4096];
579 int ret;
580
581 va_start(ap, fmt);
582 ret = vsnprintf(buf, sizeof(buf), fmt, ap);
583 va_end(ap);
584 put_buffer(s, buf, strlen(buf));
585 return ret;
586}
587#endif //CONFIG_MUXERS
588
589/* note: unlike fgets, the EOL character is not returned and a whole
590 line is parsed. return NULL if first char read was EOF */
591char *url_fgets(ByteIOContext *s, char *buf, int buf_size)
592{
593 int c;
594 char *q;
595
596 c = url_fgetc(s);
597 if (c == EOF)
598 return NULL;
599 q = buf;
600 for(;;) {
601 if (c == EOF || c == '\n')
602 break;
603 if ((q - buf) < buf_size - 1)
604 *q++ = c;
605 c = url_fgetc(s);
606 }
607 if (buf_size > 0)
608 *q = '\0';
609 return buf;
610}
611
612/*
613 * Return the maximum packet size associated to packetized buffered file
614 * handle. If the file is not packetized (stream like http or file on
615 * disk), then 0 is returned.
616 *
617 * @param h buffered file handle
618 * @return maximum packet size in bytes
619 */
620int url_fget_max_packet_size(ByteIOContext *s)
621{
622 return s->max_packet_size;
623}
624
625#ifdef CONFIG_MUXERS
626/* buffer handling */
627int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags)
628{
629 return init_put_byte(s, buf, buf_size,
630 (flags & URL_WRONLY || flags & URL_RDWR),
631 NULL, NULL, NULL, NULL);
632}
633
634/* return the written or read size */
635int url_close_buf(ByteIOContext *s)
636{
637 put_flush_packet(s);
638 return s->buf_ptr - s->buffer;
639}
640
641/* output in a dynamic buffer */
642
643typedef struct DynBuffer {
644 int pos, size, allocated_size;
645 uint8_t *buffer;
646 int io_buffer_size;
647 uint8_t io_buffer[1];
648} DynBuffer;
649
650static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size)
651{
652 DynBuffer *d = opaque;
653 int new_size, new_allocated_size;
654
655 /* reallocate buffer if needed */
656 new_size = d->pos + buf_size;
657 new_allocated_size = d->allocated_size;
658 if(new_size < d->pos || new_size > INT_MAX/2)
659 return -1;
660 while (new_size > new_allocated_size) {
661 if (!new_allocated_size)
662 new_allocated_size = new_size;
663 else
664 new_allocated_size += new_allocated_size / 2 + 1;
665 }
666
667 if (new_allocated_size > d->allocated_size) {
668 d->buffer = av_realloc(d->buffer, new_allocated_size);
669 if(d->buffer == NULL)
670 return -1234;
671 d->allocated_size = new_allocated_size;
672 }
673 memcpy(d->buffer + d->pos, buf, buf_size);
674 d->pos = new_size;
675 if (d->pos > d->size)
676 d->size = d->pos;
677 return buf_size;
678}
679
680static int dyn_packet_buf_write(void *opaque, uint8_t *buf, int buf_size)
681{
682 unsigned char buf1[4];
683 int ret;
684
685 /* packetized write: output the header */
686 buf1[0] = (buf_size >> 24);
687 buf1[1] = (buf_size >> 16);
688 buf1[2] = (buf_size >> 8);
689 buf1[3] = (buf_size);
690 ret= dyn_buf_write(opaque, buf1, 4);
691 if(ret < 0)
692 return ret;
693
694 /* then the data */
695 return dyn_buf_write(opaque, buf, buf_size);
696}
697
698static offset_t dyn_buf_seek(void *opaque, offset_t offset, int whence)
699{
700 DynBuffer *d = opaque;
701
702 if (whence == SEEK_CUR)
703 offset += d->pos;
704 else if (whence == SEEK_END)
705 offset += d->size;
706 if (offset < 0 || offset > 0x7fffffffLL)
707 return -1;
708 d->pos = offset;
709 return 0;
710}
711
712static int url_open_dyn_buf_internal(ByteIOContext *s, int max_packet_size)
713{
714 DynBuffer *d;
715 int io_buffer_size, ret;
716
717 if (max_packet_size)
718 io_buffer_size = max_packet_size;
719 else
720 io_buffer_size = 1024;
721
722 if(sizeof(DynBuffer) + io_buffer_size < io_buffer_size)
723 return -1;
724 d = av_malloc(sizeof(DynBuffer) + io_buffer_size);
725 if (!d)
726 return -1;
727 d->io_buffer_size = io_buffer_size;
728 d->buffer = NULL;
729 d->pos = 0;
730 d->size = 0;
731 d->allocated_size = 0;
732 ret = init_put_byte(s, d->io_buffer, io_buffer_size,
733 1, d, NULL,
734 max_packet_size ? dyn_packet_buf_write : dyn_buf_write,
735 max_packet_size ? NULL : dyn_buf_seek);
736 if (ret == 0) {
737 s->max_packet_size = max_packet_size;
738 }
739 return ret;
740}
741
742/*
743 * Open a write only memory stream.
744 *
745 * @param s new IO context
746 * @return zero if no error.
747 */
748int url_open_dyn_buf(ByteIOContext *s)
749{
750 return url_open_dyn_buf_internal(s, 0);
751}
752
753/*
754 * Open a write only packetized memory stream with a maximum packet
755 * size of 'max_packet_size'. The stream is stored in a memory buffer
756 * with a big endian 4 byte header giving the packet size in bytes.
757 *
758 * @param s new IO context
759 * @param max_packet_size maximum packet size (must be > 0)
760 * @return zero if no error.
761 */
762int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size)
763{
764 if (max_packet_size <= 0)
765 return -1;
766 return url_open_dyn_buf_internal(s, max_packet_size);
767}
768
769/*
770 * Return the written size and a pointer to the buffer. The buffer
771 * must be freed with av_free().
772 * @param s IO context
773 * @param pointer to a byte buffer
774 * @return the length of the byte buffer
775 */
776int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer)
777{
778 DynBuffer *d = s->opaque;
779 int size;
780
781 put_flush_packet(s);
782
783 *pbuffer = d->buffer;
784 size = d->size;
785 av_free(d);
786 return size;
787}
788#endif //CONFIG_MUXERS
Note: See TracBrowser for help on using the repository browser.