Originally committed as revision 796 to svn://svn.ffmpeg.org/ffmpeg/trunk
Fabrice Bellard authored on 2002/07/25 02:51:50... | ... |
@@ -17,6 +17,7 @@ |
17 | 17 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | 18 |
*/ |
19 | 19 |
#include "avformat.h" |
20 |
+#include <stdarg.h> |
|
20 | 21 |
|
21 | 22 |
#define IO_BUFFER_SIZE 32768 |
22 | 23 |
|
... | ... |
@@ -45,7 +46,7 @@ int init_put_byte(ByteIOContext *s, |
45 | 45 |
s->must_flush = 0; |
46 | 46 |
s->eof_reached = 0; |
47 | 47 |
s->is_streamed = 0; |
48 |
- s->packet_size = 1; |
|
48 |
+ s->max_packet_size = 0; |
|
49 | 49 |
return 0; |
50 | 50 |
} |
51 | 51 |
|
... | ... |
@@ -136,10 +137,10 @@ offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence) |
136 | 136 |
return -EPIPE; |
137 | 137 |
s->buf_ptr = s->buffer; |
138 | 138 |
s->buf_end = s->buffer; |
139 |
- s->eof_reached = 0; |
|
140 | 139 |
s->seek(s->opaque, offset, SEEK_SET); |
141 | 140 |
s->pos = offset; |
142 | 141 |
} |
142 |
+ s->eof_reached = 0; |
|
143 | 143 |
} |
144 | 144 |
return offset; |
145 | 145 |
} |
... | ... |
@@ -212,15 +213,24 @@ static void fill_buffer(ByteIOContext *s) |
212 | 212 |
{ |
213 | 213 |
int len; |
214 | 214 |
|
215 |
+ /* no need to do anything if EOF already reached */ |
|
216 |
+ if (s->eof_reached) |
|
217 |
+ return; |
|
215 | 218 |
len = s->read_packet(s->opaque, s->buffer, s->buffer_size); |
216 |
- s->pos += len; |
|
217 |
- s->buf_ptr = s->buffer; |
|
218 |
- s->buf_end = s->buffer + len; |
|
219 |
- if (len == 0) { |
|
219 |
+ if (len <= 0) { |
|
220 |
+ /* do not modify buffer if EOF reached so that a seek back can |
|
221 |
+ be done without rereading data */ |
|
220 | 222 |
s->eof_reached = 1; |
223 |
+ } else { |
|
224 |
+ s->pos += len; |
|
225 |
+ s->buf_ptr = s->buffer; |
|
226 |
+ s->buf_end = s->buffer + len; |
|
221 | 227 |
} |
222 | 228 |
} |
223 | 229 |
|
230 |
+/* NOTE: return 0 if EOF, so you cannot use it if EOF handling is |
|
231 |
+ necessary */ |
|
232 |
+/* XXX: put an inline version */ |
|
224 | 233 |
int get_byte(ByteIOContext *s) |
225 | 234 |
{ |
226 | 235 |
if (s->buf_ptr < s->buf_end) { |
... | ... |
@@ -234,6 +244,20 @@ int get_byte(ByteIOContext *s) |
234 | 234 |
} |
235 | 235 |
} |
236 | 236 |
|
237 |
+/* NOTE: return URL_EOF (-1) if EOF */ |
|
238 |
+int url_fgetc(ByteIOContext *s) |
|
239 |
+{ |
|
240 |
+ if (s->buf_ptr < s->buf_end) { |
|
241 |
+ return *s->buf_ptr++; |
|
242 |
+ } else { |
|
243 |
+ fill_buffer(s); |
|
244 |
+ if (s->buf_ptr < s->buf_end) |
|
245 |
+ return *s->buf_ptr++; |
|
246 |
+ else |
|
247 |
+ return URL_EOF; |
|
248 |
+ } |
|
249 |
+} |
|
250 |
+ |
|
237 | 251 |
int get_buffer(ByteIOContext *s, unsigned char *buf, int size) |
238 | 252 |
{ |
239 | 253 |
int len, size1; |
... | ... |
@@ -334,9 +358,15 @@ int url_seek_packet(void *opaque, INT64 offset, int whence) |
334 | 334 |
int url_fdopen(ByteIOContext *s, URLContext *h) |
335 | 335 |
{ |
336 | 336 |
UINT8 *buffer; |
337 |
- int buffer_size; |
|
337 |
+ int buffer_size, max_packet_size; |
|
338 | 338 |
|
339 |
- buffer_size = (IO_BUFFER_SIZE / h->packet_size) * h->packet_size; |
|
339 |
+ |
|
340 |
+ max_packet_size = url_get_max_packet_size(h); |
|
341 |
+ if (max_packet_size) { |
|
342 |
+ buffer_size = max_packet_size; /* no need to bufferize more than one packet */ |
|
343 |
+ } else { |
|
344 |
+ buffer_size = IO_BUFFER_SIZE; |
|
345 |
+ } |
|
340 | 346 |
buffer = av_malloc(buffer_size); |
341 | 347 |
if (!buffer) |
342 | 348 |
return -ENOMEM; |
... | ... |
@@ -348,7 +378,7 @@ int url_fdopen(ByteIOContext *s, URLContext *h) |
348 | 348 |
return -EIO; |
349 | 349 |
} |
350 | 350 |
s->is_streamed = h->is_streamed; |
351 |
- s->packet_size = h->packet_size; |
|
351 |
+ s->max_packet_size = max_packet_size; |
|
352 | 352 |
return 0; |
353 | 353 |
} |
354 | 354 |
|
... | ... |
@@ -371,6 +401,8 @@ int url_setbufsize(ByteIOContext *s, int buf_size) |
371 | 371 |
return 0; |
372 | 372 |
} |
373 | 373 |
|
374 |
+/* NOTE: when opened as read/write, the buffers are only used for |
|
375 |
+ reading */ |
|
374 | 376 |
int url_fopen(ByteIOContext *s, const char *filename, int flags) |
375 | 377 |
{ |
376 | 378 |
URLContext *h; |
... | ... |
@@ -401,6 +433,56 @@ URLContext *url_fileno(ByteIOContext *s) |
401 | 401 |
return s->opaque; |
402 | 402 |
} |
403 | 403 |
|
404 |
+/* XXX: currently size is limited */ |
|
405 |
+int url_fprintf(ByteIOContext *s, const char *fmt, ...) |
|
406 |
+{ |
|
407 |
+ va_list ap; |
|
408 |
+ char buf[4096]; |
|
409 |
+ int ret; |
|
410 |
+ |
|
411 |
+ va_start(ap, fmt); |
|
412 |
+ ret = vsnprintf(buf, sizeof(buf), fmt, ap); |
|
413 |
+ va_end(ap); |
|
414 |
+ put_buffer(s, buf, strlen(buf)); |
|
415 |
+ return ret; |
|
416 |
+} |
|
417 |
+ |
|
418 |
+/* note: unlike fgets, the EOL character is not returned and a whole |
|
419 |
+ line is parsed. return NULL if first char read was EOF */ |
|
420 |
+char *url_fgets(ByteIOContext *s, char *buf, int buf_size) |
|
421 |
+{ |
|
422 |
+ int c; |
|
423 |
+ char *q; |
|
424 |
+ |
|
425 |
+ c = url_fgetc(s); |
|
426 |
+ if (c == EOF) |
|
427 |
+ return NULL; |
|
428 |
+ q = buf; |
|
429 |
+ for(;;) { |
|
430 |
+ if (c == EOF || c == '\n') |
|
431 |
+ break; |
|
432 |
+ if ((q - buf) < buf_size - 1) |
|
433 |
+ *q++ = c; |
|
434 |
+ c = url_fgetc(s); |
|
435 |
+ } |
|
436 |
+ if (buf_size > 0) |
|
437 |
+ *q = '\0'; |
|
438 |
+ return buf; |
|
439 |
+} |
|
440 |
+ |
|
441 |
+/* |
|
442 |
+ * Return the maximum packet size associated to packetized buffered file |
|
443 |
+ * handle. If the file is not packetized (stream like http or file on |
|
444 |
+ * disk), then 0 is returned. |
|
445 |
+ * |
|
446 |
+ * @param h buffered file handle |
|
447 |
+ * @return maximum packet size in bytes |
|
448 |
+ */ |
|
449 |
+int url_fget_max_packet_size(ByteIOContext *s) |
|
450 |
+{ |
|
451 |
+ return s->max_packet_size; |
|
452 |
+} |
|
453 |
+ |
|
404 | 454 |
/* buffer handling */ |
405 | 455 |
int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags) |
406 | 456 |
{ |
... | ... |
@@ -411,5 +493,150 @@ int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags) |
411 | 411 |
/* return the written or read size */ |
412 | 412 |
int url_close_buf(ByteIOContext *s) |
413 | 413 |
{ |
414 |
+ put_flush_packet(s); |
|
414 | 415 |
return s->buf_ptr - s->buffer; |
415 | 416 |
} |
417 |
+ |
|
418 |
+/* output in a dynamic buffer */ |
|
419 |
+ |
|
420 |
+typedef struct DynBuffer { |
|
421 |
+ int pos, size, allocated_size; |
|
422 |
+ UINT8 *buffer; |
|
423 |
+ int io_buffer_size; |
|
424 |
+ UINT8 io_buffer[1]; |
|
425 |
+} DynBuffer; |
|
426 |
+ |
|
427 |
+static void dyn_buf_write(void *opaque, UINT8 *buf, int buf_size) |
|
428 |
+{ |
|
429 |
+ DynBuffer *d = opaque; |
|
430 |
+ int new_size, new_allocated_size; |
|
431 |
+ UINT8 *new_buffer; |
|
432 |
+ |
|
433 |
+ /* reallocate buffer if needed */ |
|
434 |
+ new_size = d->pos + buf_size; |
|
435 |
+ new_allocated_size = d->allocated_size; |
|
436 |
+ while (new_size > new_allocated_size) { |
|
437 |
+ if (!new_allocated_size) |
|
438 |
+ new_allocated_size = new_size; |
|
439 |
+ else |
|
440 |
+ new_allocated_size = (new_allocated_size * 3) / 2; |
|
441 |
+ } |
|
442 |
+ |
|
443 |
+ if (new_allocated_size > d->allocated_size) { |
|
444 |
+ new_buffer = av_malloc(new_allocated_size); |
|
445 |
+ if (!new_buffer) |
|
446 |
+ return; |
|
447 |
+ memcpy(new_buffer, d->buffer, d->size); |
|
448 |
+ av_free(d->buffer); |
|
449 |
+ d->buffer = new_buffer; |
|
450 |
+ d->allocated_size = new_allocated_size; |
|
451 |
+ } |
|
452 |
+ memcpy(d->buffer + d->pos, buf, buf_size); |
|
453 |
+ d->pos = new_size; |
|
454 |
+ if (d->pos > d->size) |
|
455 |
+ d->size = d->pos; |
|
456 |
+} |
|
457 |
+ |
|
458 |
+static void dyn_packet_buf_write(void *opaque, UINT8 *buf, int buf_size) |
|
459 |
+{ |
|
460 |
+ unsigned char buf1[4]; |
|
461 |
+ |
|
462 |
+ /* packetized write: output the header */ |
|
463 |
+ buf1[0] = (buf_size >> 24); |
|
464 |
+ buf1[1] = (buf_size >> 16); |
|
465 |
+ buf1[2] = (buf_size >> 8); |
|
466 |
+ buf1[3] = (buf_size); |
|
467 |
+ dyn_buf_write(opaque, buf1, 4); |
|
468 |
+ |
|
469 |
+ /* then the data */ |
|
470 |
+ dyn_buf_write(opaque, buf, buf_size); |
|
471 |
+} |
|
472 |
+ |
|
473 |
+static int dyn_buf_seek(void *opaque, offset_t offset, int whence) |
|
474 |
+{ |
|
475 |
+ DynBuffer *d = opaque; |
|
476 |
+ |
|
477 |
+ if (whence == SEEK_CUR) |
|
478 |
+ offset += d->pos; |
|
479 |
+ else if (whence == SEEK_END) |
|
480 |
+ offset += d->size; |
|
481 |
+ if (offset < 0 || offset > 0x7fffffffLL) |
|
482 |
+ return -1; |
|
483 |
+ d->pos = offset; |
|
484 |
+ return 0; |
|
485 |
+} |
|
486 |
+ |
|
487 |
+static int url_open_dyn_buf_internal(ByteIOContext *s, int max_packet_size) |
|
488 |
+{ |
|
489 |
+ DynBuffer *d; |
|
490 |
+ int io_buffer_size, ret; |
|
491 |
+ |
|
492 |
+ if (max_packet_size) |
|
493 |
+ io_buffer_size = max_packet_size; |
|
494 |
+ else |
|
495 |
+ io_buffer_size = 1024; |
|
496 |
+ |
|
497 |
+ d = av_malloc(sizeof(DynBuffer) + io_buffer_size); |
|
498 |
+ if (!d) |
|
499 |
+ return -1; |
|
500 |
+ d->io_buffer_size = io_buffer_size; |
|
501 |
+ d->buffer = NULL; |
|
502 |
+ d->pos = 0; |
|
503 |
+ d->size = 0; |
|
504 |
+ d->allocated_size = 0; |
|
505 |
+ ret = init_put_byte(s, d->io_buffer, io_buffer_size, |
|
506 |
+ 1, d, NULL, |
|
507 |
+ max_packet_size ? dyn_packet_buf_write : dyn_buf_write, |
|
508 |
+ max_packet_size ? NULL : dyn_buf_seek); |
|
509 |
+ if (ret == 0) { |
|
510 |
+ s->max_packet_size = max_packet_size; |
|
511 |
+ } |
|
512 |
+ return ret; |
|
513 |
+} |
|
514 |
+ |
|
515 |
+/* |
|
516 |
+ * Open a write only memory stream. |
|
517 |
+ * |
|
518 |
+ * @param s new IO context |
|
519 |
+ * @return zero if no error. |
|
520 |
+ */ |
|
521 |
+int url_open_dyn_buf(ByteIOContext *s) |
|
522 |
+{ |
|
523 |
+ return url_open_dyn_buf_internal(s, 0); |
|
524 |
+} |
|
525 |
+ |
|
526 |
+/* |
|
527 |
+ * Open a write only packetized memory stream with a maximum packet |
|
528 |
+ * size of 'max_packet_size'. The stream is stored in a memory buffer |
|
529 |
+ * with a big endian 4 byte header giving the packet size in bytes. |
|
530 |
+ * |
|
531 |
+ * @param s new IO context |
|
532 |
+ * @param max_packet_size maximum packet size (must be > 0) |
|
533 |
+ * @return zero if no error. |
|
534 |
+ */ |
|
535 |
+int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size) |
|
536 |
+{ |
|
537 |
+ if (max_packet_size <= 0) |
|
538 |
+ return -1; |
|
539 |
+ return url_open_dyn_buf_internal(s, max_packet_size); |
|
540 |
+} |
|
541 |
+ |
|
542 |
+/* |
|
543 |
+ * Return the written size and a pointer to the buffer. The buffer |
|
544 |
+ * must be freed with av_free(). |
|
545 |
+ * @param s IO context |
|
546 |
+ * @param pointer to a byte buffer |
|
547 |
+ * @return the length of the byte buffer |
|
548 |
+ */ |
|
549 |
+int url_close_dyn_buf(ByteIOContext *s, UINT8 **pbuffer) |
|
550 |
+{ |
|
551 |
+ DynBuffer *d = s->opaque; |
|
552 |
+ int size; |
|
553 |
+ |
|
554 |
+ put_flush_packet(s); |
|
555 |
+ |
|
556 |
+ *pbuffer = d->buffer; |
|
557 |
+ size = d->size; |
|
558 |
+ av_free(d); |
|
559 |
+ return size; |
|
560 |
+} |