Mercurial > libavformat.hg
comparison aviobuf.c @ 0:05318cf2e886 libavformat
renamed libav to libavformat
author | bellard |
---|---|
date | Mon, 25 Nov 2002 19:07:40 +0000 |
parents | |
children | b0e0eb595e29 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:05318cf2e886 |
---|---|
1 /* | |
2 * Buffered I/O for ffmpeg system | |
3 * Copyright (c) 2000,2001 Fabrice Bellard | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 #include "avformat.h" | |
20 #include <stdarg.h> | |
21 | |
22 #define IO_BUFFER_SIZE 32768 | |
23 | |
24 int init_put_byte(ByteIOContext *s, | |
25 unsigned char *buffer, | |
26 int buffer_size, | |
27 int write_flag, | |
28 void *opaque, | |
29 int (*read_packet)(void *opaque, UINT8 *buf, int buf_size), | |
30 void (*write_packet)(void *opaque, UINT8 *buf, int buf_size), | |
31 int (*seek)(void *opaque, offset_t offset, int whence)) | |
32 { | |
33 s->buffer = buffer; | |
34 s->buffer_size = buffer_size; | |
35 s->buf_ptr = buffer; | |
36 s->write_flag = write_flag; | |
37 if (!s->write_flag) | |
38 s->buf_end = buffer; | |
39 else | |
40 s->buf_end = buffer + buffer_size; | |
41 s->opaque = opaque; | |
42 s->write_packet = write_packet; | |
43 s->read_packet = read_packet; | |
44 s->seek = seek; | |
45 s->pos = 0; | |
46 s->must_flush = 0; | |
47 s->eof_reached = 0; | |
48 s->is_streamed = 0; | |
49 s->max_packet_size = 0; | |
50 return 0; | |
51 } | |
52 | |
53 | |
54 static void flush_buffer(ByteIOContext *s) | |
55 { | |
56 if (s->buf_ptr > s->buffer) { | |
57 if (s->write_packet) | |
58 s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer); | |
59 s->pos += s->buf_ptr - s->buffer; | |
60 } | |
61 s->buf_ptr = s->buffer; | |
62 } | |
63 | |
64 void put_byte(ByteIOContext *s, int b) | |
65 { | |
66 *(s->buf_ptr)++ = b; | |
67 if (s->buf_ptr >= s->buf_end) | |
68 flush_buffer(s); | |
69 } | |
70 | |
71 void put_buffer(ByteIOContext *s, const unsigned char *buf, int size) | |
72 { | |
73 int len; | |
74 | |
75 while (size > 0) { | |
76 len = (s->buf_end - s->buf_ptr); | |
77 if (len > size) | |
78 len = size; | |
79 memcpy(s->buf_ptr, buf, len); | |
80 s->buf_ptr += len; | |
81 | |
82 if (s->buf_ptr >= s->buf_end) | |
83 flush_buffer(s); | |
84 | |
85 buf += len; | |
86 size -= len; | |
87 } | |
88 } | |
89 | |
90 void put_flush_packet(ByteIOContext *s) | |
91 { | |
92 flush_buffer(s); | |
93 s->must_flush = 0; | |
94 } | |
95 | |
96 offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence) | |
97 { | |
98 offset_t offset1; | |
99 | |
100 if (whence != SEEK_CUR && whence != SEEK_SET) | |
101 return -EINVAL; | |
102 | |
103 if (s->write_flag) { | |
104 if (whence == SEEK_CUR) { | |
105 offset1 = s->pos + (s->buf_ptr - s->buffer); | |
106 if (offset == 0) | |
107 return offset1; | |
108 offset += offset1; | |
109 } | |
110 offset1 = offset - s->pos; | |
111 if (!s->must_flush && | |
112 offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) { | |
113 /* can do the seek inside the buffer */ | |
114 s->buf_ptr = s->buffer + offset1; | |
115 } else { | |
116 if (!s->seek) | |
117 return -EPIPE; | |
118 flush_buffer(s); | |
119 s->must_flush = 1; | |
120 s->buf_ptr = s->buffer; | |
121 s->seek(s->opaque, offset, SEEK_SET); | |
122 s->pos = offset; | |
123 } | |
124 } else { | |
125 if (whence == SEEK_CUR) { | |
126 offset1 = s->pos - (s->buf_end - s->buffer) + (s->buf_ptr - s->buffer); | |
127 if (offset == 0) | |
128 return offset1; | |
129 offset += offset1; | |
130 } | |
131 offset1 = offset - (s->pos - (s->buf_end - s->buffer)); | |
132 if (offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) { | |
133 /* can do the seek inside the buffer */ | |
134 s->buf_ptr = s->buffer + offset1; | |
135 } else { | |
136 if (!s->seek) | |
137 return -EPIPE; | |
138 s->buf_ptr = s->buffer; | |
139 s->buf_end = s->buffer; | |
140 s->seek(s->opaque, offset, SEEK_SET); | |
141 s->pos = offset; | |
142 } | |
143 s->eof_reached = 0; | |
144 } | |
145 return offset; | |
146 } | |
147 | |
148 void url_fskip(ByteIOContext *s, offset_t offset) | |
149 { | |
150 url_fseek(s, offset, SEEK_CUR); | |
151 } | |
152 | |
153 offset_t url_ftell(ByteIOContext *s) | |
154 { | |
155 return url_fseek(s, 0, SEEK_CUR); | |
156 } | |
157 | |
158 int url_feof(ByteIOContext *s) | |
159 { | |
160 return s->eof_reached; | |
161 } | |
162 | |
163 void put_le32(ByteIOContext *s, unsigned int val) | |
164 { | |
165 put_byte(s, val); | |
166 put_byte(s, val >> 8); | |
167 put_byte(s, val >> 16); | |
168 put_byte(s, val >> 24); | |
169 } | |
170 | |
171 void put_be32(ByteIOContext *s, unsigned int val) | |
172 { | |
173 put_byte(s, val >> 24); | |
174 put_byte(s, val >> 16); | |
175 put_byte(s, val >> 8); | |
176 put_byte(s, val); | |
177 } | |
178 | |
179 /* IEEE format is assumed */ | |
180 void put_be64_double(ByteIOContext *s, double val) | |
181 { | |
182 union { | |
183 double d; | |
184 UINT64 ull; | |
185 } u; | |
186 u.d = val; | |
187 put_be64(s, u.ull); | |
188 } | |
189 | |
190 void put_strz(ByteIOContext *s, const char *str) | |
191 { | |
192 if (str) | |
193 put_buffer(s, (const unsigned char *) str, strlen(str) + 1); | |
194 else | |
195 put_byte(s, 0); | |
196 } | |
197 | |
198 void put_le64(ByteIOContext *s, UINT64 val) | |
199 { | |
200 put_le32(s, (UINT32)(val & 0xffffffff)); | |
201 put_le32(s, (UINT32)(val >> 32)); | |
202 } | |
203 | |
204 void put_be64(ByteIOContext *s, UINT64 val) | |
205 { | |
206 put_be32(s, (UINT32)(val >> 32)); | |
207 put_be32(s, (UINT32)(val & 0xffffffff)); | |
208 } | |
209 | |
210 void put_le16(ByteIOContext *s, unsigned int val) | |
211 { | |
212 put_byte(s, val); | |
213 put_byte(s, val >> 8); | |
214 } | |
215 | |
216 void put_be16(ByteIOContext *s, unsigned int val) | |
217 { | |
218 put_byte(s, val >> 8); | |
219 put_byte(s, val); | |
220 } | |
221 | |
222 void put_tag(ByteIOContext *s, const char *tag) | |
223 { | |
224 while (*tag) { | |
225 put_byte(s, *tag++); | |
226 } | |
227 } | |
228 | |
229 /* Input stream */ | |
230 | |
231 static void fill_buffer(ByteIOContext *s) | |
232 { | |
233 int len; | |
234 | |
235 /* no need to do anything if EOF already reached */ | |
236 if (s->eof_reached) | |
237 return; | |
238 len = s->read_packet(s->opaque, s->buffer, s->buffer_size); | |
239 if (len <= 0) { | |
240 /* do not modify buffer if EOF reached so that a seek back can | |
241 be done without rereading data */ | |
242 s->eof_reached = 1; | |
243 } else { | |
244 s->pos += len; | |
245 s->buf_ptr = s->buffer; | |
246 s->buf_end = s->buffer + len; | |
247 } | |
248 } | |
249 | |
250 /* NOTE: return 0 if EOF, so you cannot use it if EOF handling is | |
251 necessary */ | |
252 /* XXX: put an inline version */ | |
253 int get_byte(ByteIOContext *s) | |
254 { | |
255 if (s->buf_ptr < s->buf_end) { | |
256 return *s->buf_ptr++; | |
257 } else { | |
258 fill_buffer(s); | |
259 if (s->buf_ptr < s->buf_end) | |
260 return *s->buf_ptr++; | |
261 else | |
262 return 0; | |
263 } | |
264 } | |
265 | |
266 /* NOTE: return URL_EOF (-1) if EOF */ | |
267 int url_fgetc(ByteIOContext *s) | |
268 { | |
269 if (s->buf_ptr < s->buf_end) { | |
270 return *s->buf_ptr++; | |
271 } else { | |
272 fill_buffer(s); | |
273 if (s->buf_ptr < s->buf_end) | |
274 return *s->buf_ptr++; | |
275 else | |
276 return URL_EOF; | |
277 } | |
278 } | |
279 | |
280 int get_buffer(ByteIOContext *s, unsigned char *buf, int size) | |
281 { | |
282 int len, size1; | |
283 | |
284 size1 = size; | |
285 while (size > 0) { | |
286 len = s->buf_end - s->buf_ptr; | |
287 if (len > size) | |
288 len = size; | |
289 if (len == 0) { | |
290 fill_buffer(s); | |
291 len = s->buf_end - s->buf_ptr; | |
292 if (len == 0) | |
293 break; | |
294 } else { | |
295 memcpy(buf, s->buf_ptr, len); | |
296 buf += len; | |
297 s->buf_ptr += len; | |
298 size -= len; | |
299 } | |
300 } | |
301 return size1 - size; | |
302 } | |
303 | |
304 unsigned int get_le16(ByteIOContext *s) | |
305 { | |
306 unsigned int val; | |
307 val = get_byte(s); | |
308 val |= get_byte(s) << 8; | |
309 return val; | |
310 } | |
311 | |
312 unsigned int get_le32(ByteIOContext *s) | |
313 { | |
314 unsigned int val; | |
315 val = get_byte(s); | |
316 val |= get_byte(s) << 8; | |
317 val |= get_byte(s) << 16; | |
318 val |= get_byte(s) << 24; | |
319 return val; | |
320 } | |
321 | |
322 UINT64 get_le64(ByteIOContext *s) | |
323 { | |
324 UINT64 val; | |
325 val = (UINT64)get_le32(s); | |
326 val |= (UINT64)get_le32(s) << 32; | |
327 return val; | |
328 } | |
329 | |
330 unsigned int get_be16(ByteIOContext *s) | |
331 { | |
332 unsigned int val; | |
333 val = get_byte(s) << 8; | |
334 val |= get_byte(s); | |
335 return val; | |
336 } | |
337 | |
338 unsigned int get_be32(ByteIOContext *s) | |
339 { | |
340 unsigned int val; | |
341 val = get_byte(s) << 24; | |
342 val |= get_byte(s) << 16; | |
343 val |= get_byte(s) << 8; | |
344 val |= get_byte(s); | |
345 return val; | |
346 } | |
347 | |
348 double get_be64_double(ByteIOContext *s) | |
349 { | |
350 union { | |
351 double d; | |
352 UINT64 ull; | |
353 } u; | |
354 | |
355 u.ull = get_be64(s); | |
356 return u.d; | |
357 } | |
358 | |
359 char *get_strz(ByteIOContext *s, char *buf, int maxlen) | |
360 { | |
361 int i = 0; | |
362 char c; | |
363 | |
364 while ((c = get_byte(s))) { | |
365 if (i < maxlen-1) | |
366 buf[i++] = c; | |
367 } | |
368 | |
369 buf[i] = 0; /* Ensure null terminated, but may be truncated */ | |
370 | |
371 return buf; | |
372 } | |
373 | |
374 UINT64 get_be64(ByteIOContext *s) | |
375 { | |
376 UINT64 val; | |
377 val = (UINT64)get_be32(s) << 32; | |
378 val |= (UINT64)get_be32(s); | |
379 return val; | |
380 } | |
381 | |
382 /* link with avio functions */ | |
383 | |
384 void url_write_packet(void *opaque, UINT8 *buf, int buf_size) | |
385 { | |
386 URLContext *h = opaque; | |
387 url_write(h, buf, buf_size); | |
388 } | |
389 | |
390 int url_read_packet(void *opaque, UINT8 *buf, int buf_size) | |
391 { | |
392 URLContext *h = opaque; | |
393 return url_read(h, buf, buf_size); | |
394 } | |
395 | |
396 int url_seek_packet(void *opaque, INT64 offset, int whence) | |
397 { | |
398 URLContext *h = opaque; | |
399 url_seek(h, offset, whence); | |
400 return 0; | |
401 } | |
402 | |
403 int url_fdopen(ByteIOContext *s, URLContext *h) | |
404 { | |
405 UINT8 *buffer; | |
406 int buffer_size, max_packet_size; | |
407 | |
408 | |
409 max_packet_size = url_get_max_packet_size(h); | |
410 if (max_packet_size) { | |
411 buffer_size = max_packet_size; /* no need to bufferize more than one packet */ | |
412 } else { | |
413 buffer_size = IO_BUFFER_SIZE; | |
414 } | |
415 buffer = av_malloc(buffer_size); | |
416 if (!buffer) | |
417 return -ENOMEM; | |
418 | |
419 if (init_put_byte(s, buffer, buffer_size, | |
420 (h->flags & URL_WRONLY) != 0, h, | |
421 url_read_packet, url_write_packet, url_seek_packet) < 0) { | |
422 av_free(buffer); | |
423 return -EIO; | |
424 } | |
425 s->is_streamed = h->is_streamed; | |
426 s->max_packet_size = max_packet_size; | |
427 return 0; | |
428 } | |
429 | |
430 /* XXX: must be called before any I/O */ | |
431 int url_setbufsize(ByteIOContext *s, int buf_size) | |
432 { | |
433 UINT8 *buffer; | |
434 buffer = av_malloc(buf_size); | |
435 if (!buffer) | |
436 return -ENOMEM; | |
437 | |
438 av_free(s->buffer); | |
439 s->buffer = buffer; | |
440 s->buffer_size = buf_size; | |
441 s->buf_ptr = buffer; | |
442 if (!s->write_flag) | |
443 s->buf_end = buffer; | |
444 else | |
445 s->buf_end = buffer + buf_size; | |
446 return 0; | |
447 } | |
448 | |
449 /* NOTE: when opened as read/write, the buffers are only used for | |
450 reading */ | |
451 int url_fopen(ByteIOContext *s, const char *filename, int flags) | |
452 { | |
453 URLContext *h; | |
454 int err; | |
455 | |
456 err = url_open(&h, filename, flags); | |
457 if (err < 0) | |
458 return err; | |
459 err = url_fdopen(s, h); | |
460 if (err < 0) { | |
461 url_close(h); | |
462 return err; | |
463 } | |
464 return 0; | |
465 } | |
466 | |
467 int url_fclose(ByteIOContext *s) | |
468 { | |
469 URLContext *h = s->opaque; | |
470 | |
471 av_free(s->buffer); | |
472 memset(s, 0, sizeof(ByteIOContext)); | |
473 return url_close(h); | |
474 } | |
475 | |
476 URLContext *url_fileno(ByteIOContext *s) | |
477 { | |
478 return s->opaque; | |
479 } | |
480 | |
481 /* XXX: currently size is limited */ | |
482 int url_fprintf(ByteIOContext *s, const char *fmt, ...) | |
483 { | |
484 va_list ap; | |
485 char buf[4096]; | |
486 int ret; | |
487 | |
488 va_start(ap, fmt); | |
489 ret = vsnprintf(buf, sizeof(buf), fmt, ap); | |
490 va_end(ap); | |
491 put_buffer(s, buf, strlen(buf)); | |
492 return ret; | |
493 } | |
494 | |
495 /* note: unlike fgets, the EOL character is not returned and a whole | |
496 line is parsed. return NULL if first char read was EOF */ | |
497 char *url_fgets(ByteIOContext *s, char *buf, int buf_size) | |
498 { | |
499 int c; | |
500 char *q; | |
501 | |
502 c = url_fgetc(s); | |
503 if (c == EOF) | |
504 return NULL; | |
505 q = buf; | |
506 for(;;) { | |
507 if (c == EOF || c == '\n') | |
508 break; | |
509 if ((q - buf) < buf_size - 1) | |
510 *q++ = c; | |
511 c = url_fgetc(s); | |
512 } | |
513 if (buf_size > 0) | |
514 *q = '\0'; | |
515 return buf; | |
516 } | |
517 | |
518 /* | |
519 * Return the maximum packet size associated to packetized buffered file | |
520 * handle. If the file is not packetized (stream like http or file on | |
521 * disk), then 0 is returned. | |
522 * | |
523 * @param h buffered file handle | |
524 * @return maximum packet size in bytes | |
525 */ | |
526 int url_fget_max_packet_size(ByteIOContext *s) | |
527 { | |
528 return s->max_packet_size; | |
529 } | |
530 | |
531 /* buffer handling */ | |
532 int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags) | |
533 { | |
534 return init_put_byte(s, buf, buf_size, | |
535 (flags & URL_WRONLY) != 0, NULL, NULL, NULL, NULL); | |
536 } | |
537 | |
538 /* return the written or read size */ | |
539 int url_close_buf(ByteIOContext *s) | |
540 { | |
541 put_flush_packet(s); | |
542 return s->buf_ptr - s->buffer; | |
543 } | |
544 | |
545 /* output in a dynamic buffer */ | |
546 | |
547 typedef struct DynBuffer { | |
548 int pos, size, allocated_size; | |
549 UINT8 *buffer; | |
550 int io_buffer_size; | |
551 UINT8 io_buffer[1]; | |
552 } DynBuffer; | |
553 | |
554 static void dyn_buf_write(void *opaque, UINT8 *buf, int buf_size) | |
555 { | |
556 DynBuffer *d = opaque; | |
557 int new_size, new_allocated_size; | |
558 UINT8 *new_buffer; | |
559 | |
560 /* reallocate buffer if needed */ | |
561 new_size = d->pos + buf_size; | |
562 new_allocated_size = d->allocated_size; | |
563 while (new_size > new_allocated_size) { | |
564 if (!new_allocated_size) | |
565 new_allocated_size = new_size; | |
566 else | |
567 new_allocated_size = (new_allocated_size * 3) / 2 + 1; | |
568 } | |
569 | |
570 if (new_allocated_size > d->allocated_size) { | |
571 new_buffer = av_malloc(new_allocated_size); | |
572 if (!new_buffer) | |
573 return; | |
574 memcpy(new_buffer, d->buffer, d->size); | |
575 av_free(d->buffer); | |
576 d->buffer = new_buffer; | |
577 d->allocated_size = new_allocated_size; | |
578 } | |
579 memcpy(d->buffer + d->pos, buf, buf_size); | |
580 d->pos = new_size; | |
581 if (d->pos > d->size) | |
582 d->size = d->pos; | |
583 } | |
584 | |
585 static void dyn_packet_buf_write(void *opaque, UINT8 *buf, int buf_size) | |
586 { | |
587 unsigned char buf1[4]; | |
588 | |
589 /* packetized write: output the header */ | |
590 buf1[0] = (buf_size >> 24); | |
591 buf1[1] = (buf_size >> 16); | |
592 buf1[2] = (buf_size >> 8); | |
593 buf1[3] = (buf_size); | |
594 dyn_buf_write(opaque, buf1, 4); | |
595 | |
596 /* then the data */ | |
597 dyn_buf_write(opaque, buf, buf_size); | |
598 } | |
599 | |
600 static int dyn_buf_seek(void *opaque, offset_t offset, int whence) | |
601 { | |
602 DynBuffer *d = opaque; | |
603 | |
604 if (whence == SEEK_CUR) | |
605 offset += d->pos; | |
606 else if (whence == SEEK_END) | |
607 offset += d->size; | |
608 if (offset < 0 || offset > 0x7fffffffLL) | |
609 return -1; | |
610 d->pos = offset; | |
611 return 0; | |
612 } | |
613 | |
614 static int url_open_dyn_buf_internal(ByteIOContext *s, int max_packet_size) | |
615 { | |
616 DynBuffer *d; | |
617 int io_buffer_size, ret; | |
618 | |
619 if (max_packet_size) | |
620 io_buffer_size = max_packet_size; | |
621 else | |
622 io_buffer_size = 1024; | |
623 | |
624 d = av_malloc(sizeof(DynBuffer) + io_buffer_size); | |
625 if (!d) | |
626 return -1; | |
627 d->io_buffer_size = io_buffer_size; | |
628 d->buffer = NULL; | |
629 d->pos = 0; | |
630 d->size = 0; | |
631 d->allocated_size = 0; | |
632 ret = init_put_byte(s, d->io_buffer, io_buffer_size, | |
633 1, d, NULL, | |
634 max_packet_size ? dyn_packet_buf_write : dyn_buf_write, | |
635 max_packet_size ? NULL : dyn_buf_seek); | |
636 if (ret == 0) { | |
637 s->max_packet_size = max_packet_size; | |
638 } | |
639 return ret; | |
640 } | |
641 | |
642 /* | |
643 * Open a write only memory stream. | |
644 * | |
645 * @param s new IO context | |
646 * @return zero if no error. | |
647 */ | |
648 int url_open_dyn_buf(ByteIOContext *s) | |
649 { | |
650 return url_open_dyn_buf_internal(s, 0); | |
651 } | |
652 | |
653 /* | |
654 * Open a write only packetized memory stream with a maximum packet | |
655 * size of 'max_packet_size'. The stream is stored in a memory buffer | |
656 * with a big endian 4 byte header giving the packet size in bytes. | |
657 * | |
658 * @param s new IO context | |
659 * @param max_packet_size maximum packet size (must be > 0) | |
660 * @return zero if no error. | |
661 */ | |
662 int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size) | |
663 { | |
664 if (max_packet_size <= 0) | |
665 return -1; | |
666 return url_open_dyn_buf_internal(s, max_packet_size); | |
667 } | |
668 | |
669 /* | |
670 * Return the written size and a pointer to the buffer. The buffer | |
671 * must be freed with av_free(). | |
672 * @param s IO context | |
673 * @param pointer to a byte buffer | |
674 * @return the length of the byte buffer | |
675 */ | |
676 int url_close_dyn_buf(ByteIOContext *s, UINT8 **pbuffer) | |
677 { | |
678 DynBuffer *d = s->opaque; | |
679 int size; | |
680 | |
681 put_flush_packet(s); | |
682 | |
683 *pbuffer = d->buffer; | |
684 size = d->size; | |
685 av_free(d); | |
686 return size; | |
687 } |