2 * Buffered I/O for ffmpeg system
3 * Copyright (c) 2000,2001 Fabrice Bellard
5 * This file is part of FFmpeg.
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.
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.
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
22 #include "libavutil/crc.h"
27 #define IO_BUFFER_SIZE 32768
29 static void fill_buffer(ByteIOContext
*s
);
31 int init_put_byte(ByteIOContext
*s
,
32 unsigned char *buffer
,
36 int (*read_packet
)(void *opaque
, uint8_t *buf
, int buf_size
),
37 int (*write_packet
)(void *opaque
, uint8_t *buf
, int buf_size
),
38 offset_t (*seek
)(void *opaque
, offset_t offset
, int whence
))
41 s
->buffer_size
= buffer_size
;
43 url_resetbuf(s
, write_flag
? URL_WRONLY
: URL_RDONLY
);
45 s
->write_packet
= write_packet
;
46 s
->read_packet
= read_packet
;
53 s
->max_packet_size
= 0;
54 s
->update_checksum
= NULL
;
55 if(!read_packet
&& !write_flag
){
57 s
->buf_end
= s
->buffer
+ buffer_size
;
64 ByteIOContext
*av_alloc_put_byte(
65 unsigned char *buffer
,
69 int (*read_packet
)(void *opaque
, uint8_t *buf
, int buf_size
),
70 int (*write_packet
)(void *opaque
, uint8_t *buf
, int buf_size
),
71 offset_t (*seek
)(void *opaque
, offset_t offset
, int whence
)) {
72 ByteIOContext
*s
= av_mallocz(sizeof(ByteIOContext
));
73 init_put_byte(s
, buffer
, buffer_size
, write_flag
, opaque
,
74 read_packet
, write_packet
, seek
);
78 static void flush_buffer(ByteIOContext
*s
)
80 if (s
->buf_ptr
> s
->buffer
) {
81 if (s
->write_packet
&& !s
->error
){
82 int ret
= s
->write_packet(s
->opaque
, s
->buffer
, s
->buf_ptr
- s
->buffer
);
87 if(s
->update_checksum
){
88 s
->checksum
= s
->update_checksum(s
->checksum
, s
->checksum_ptr
, s
->buf_ptr
- s
->checksum_ptr
);
89 s
->checksum_ptr
= s
->buffer
;
91 s
->pos
+= s
->buf_ptr
- s
->buffer
;
93 s
->buf_ptr
= s
->buffer
;
96 void put_byte(ByteIOContext
*s
, int b
)
99 if (s
->buf_ptr
>= s
->buf_end
)
103 void put_buffer(ByteIOContext
*s
, const unsigned char *buf
, int size
)
108 len
= (s
->buf_end
- s
->buf_ptr
);
111 memcpy(s
->buf_ptr
, buf
, len
);
114 if (s
->buf_ptr
>= s
->buf_end
)
122 void put_flush_packet(ByteIOContext
*s
)
128 offset_t
url_fseek(ByteIOContext
*s
, offset_t offset
, int whence
)
134 return AVERROR(EINVAL
);
136 pos
= s
->pos
- (s
->write_flag
? 0 : (s
->buf_end
- s
->buffer
));
138 if (whence
!= SEEK_CUR
&& whence
!= SEEK_SET
)
139 return AVERROR(EINVAL
);
141 if (whence
== SEEK_CUR
) {
142 offset1
= pos
+ (s
->buf_ptr
- s
->buffer
);
147 offset1
= offset
- pos
;
148 if (!s
->must_flush
&&
149 offset1
>= 0 && offset1
< (s
->buf_end
- s
->buffer
)) {
150 /* can do the seek inside the buffer */
151 s
->buf_ptr
= s
->buffer
+ offset1
;
152 } else if(s
->is_streamed
&& !s
->write_flag
&&
153 offset1
>= 0 && offset1
< (s
->buf_end
- s
->buffer
) + (1<<16)){
154 while(s
->pos
< offset
&& !s
->eof_reached
)
157 return AVERROR(EPIPE
);
158 s
->buf_ptr
= s
->buf_end
+ offset
- s
->pos
;
160 offset_t res
= AVERROR(EPIPE
);
162 #if defined(CONFIG_MUXERS) || defined(CONFIG_NETWORK)
167 #endif /* defined(CONFIG_MUXERS) || defined(CONFIG_NETWORK) */
169 s
->buf_end
= s
->buffer
;
171 s
->buf_ptr
= s
->buffer
;
172 if (!s
->seek
|| (res
= s
->seek(s
->opaque
, offset
, SEEK_SET
)) < 0)
180 void url_fskip(ByteIOContext
*s
, offset_t offset
)
182 url_fseek(s
, offset
, SEEK_CUR
);
185 offset_t
url_ftell(ByteIOContext
*s
)
187 return url_fseek(s
, 0, SEEK_CUR
);
190 offset_t
url_fsize(ByteIOContext
*s
)
195 return AVERROR(EINVAL
);
198 return AVERROR(EPIPE
);
199 size
= s
->seek(s
->opaque
, 0, AVSEEK_SIZE
);
201 if ((size
= s
->seek(s
->opaque
, -1, SEEK_END
)) < 0)
204 s
->seek(s
->opaque
, s
->pos
, SEEK_SET
);
209 int url_feof(ByteIOContext
*s
)
213 return s
->eof_reached
;
216 int url_ferror(ByteIOContext
*s
)
223 void put_le32(ByteIOContext
*s
, unsigned int val
)
226 put_byte(s
, val
>> 8);
227 put_byte(s
, val
>> 16);
228 put_byte(s
, val
>> 24);
231 void put_be32(ByteIOContext
*s
, unsigned int val
)
233 put_byte(s
, val
>> 24);
234 put_byte(s
, val
>> 16);
235 put_byte(s
, val
>> 8);
239 void put_strz(ByteIOContext
*s
, const char *str
)
242 put_buffer(s
, (const unsigned char *) str
, strlen(str
) + 1);
247 void put_le64(ByteIOContext
*s
, uint64_t val
)
249 put_le32(s
, (uint32_t)(val
& 0xffffffff));
250 put_le32(s
, (uint32_t)(val
>> 32));
253 void put_be64(ByteIOContext
*s
, uint64_t val
)
255 put_be32(s
, (uint32_t)(val
>> 32));
256 put_be32(s
, (uint32_t)(val
& 0xffffffff));
259 void put_le16(ByteIOContext
*s
, unsigned int val
)
262 put_byte(s
, val
>> 8);
265 void put_be16(ByteIOContext
*s
, unsigned int val
)
267 put_byte(s
, val
>> 8);
271 void put_le24(ByteIOContext
*s
, unsigned int val
)
273 put_le16(s
, val
& 0xffff);
274 put_byte(s
, val
>> 16);
277 void put_be24(ByteIOContext
*s
, unsigned int val
)
279 put_be16(s
, val
>> 8);
283 void put_tag(ByteIOContext
*s
, const char *tag
)
292 static void fill_buffer(ByteIOContext
*s
)
296 /* no need to do anything if EOF already reached */
300 if(s
->update_checksum
){
301 if(s
->buf_end
> s
->checksum_ptr
)
302 s
->checksum
= s
->update_checksum(s
->checksum
, s
->checksum_ptr
, s
->buf_end
- s
->checksum_ptr
);
303 s
->checksum_ptr
= s
->buffer
;
307 len
= s
->read_packet(s
->opaque
, s
->buffer
, s
->buffer_size
);
309 /* do not modify buffer if EOF reached so that a seek back can
310 be done without rereading data */
316 s
->buf_ptr
= s
->buffer
;
317 s
->buf_end
= s
->buffer
+ len
;
321 unsigned long ff_crc04C11DB7_update(unsigned long checksum
, const uint8_t *buf
, unsigned int len
){
322 return av_crc(av_crc_get_table(AV_CRC_32_IEEE
), checksum
, buf
, len
);
325 unsigned long get_checksum(ByteIOContext
*s
){
326 s
->checksum
= s
->update_checksum(s
->checksum
, s
->checksum_ptr
, s
->buf_ptr
- s
->checksum_ptr
);
327 s
->update_checksum
= NULL
;
331 void init_checksum(ByteIOContext
*s
, unsigned long (*update_checksum
)(unsigned long c
, const uint8_t *p
, unsigned int len
), unsigned long checksum
){
332 s
->update_checksum
= update_checksum
;
333 if(s
->update_checksum
){
334 s
->checksum
= checksum
;
335 s
->checksum_ptr
= s
->buf_ptr
;
339 /* XXX: put an inline version */
340 int get_byte(ByteIOContext
*s
)
342 if (s
->buf_ptr
< s
->buf_end
) {
343 return *s
->buf_ptr
++;
346 if (s
->buf_ptr
< s
->buf_end
)
347 return *s
->buf_ptr
++;
353 int url_fgetc(ByteIOContext
*s
)
355 if (s
->buf_ptr
< s
->buf_end
) {
356 return *s
->buf_ptr
++;
359 if (s
->buf_ptr
< s
->buf_end
)
360 return *s
->buf_ptr
++;
366 int get_buffer(ByteIOContext
*s
, unsigned char *buf
, int size
)
372 len
= s
->buf_end
- s
->buf_ptr
;
376 if(size
> s
->buffer_size
&& !s
->update_checksum
){
378 len
= s
->read_packet(s
->opaque
, buf
, size
);
380 /* do not modify buffer if EOF reached so that a seek back can
381 be done without rereading data */
390 s
->buf_ptr
= s
->buffer
;
391 s
->buf_end
= s
->buffer
/* + len*/;
395 len
= s
->buf_end
- s
->buf_ptr
;
400 memcpy(buf
, s
->buf_ptr
, len
);
409 int get_partial_buffer(ByteIOContext
*s
, unsigned char *buf
, int size
)
416 len
= s
->buf_end
- s
->buf_ptr
;
419 len
= s
->buf_end
- s
->buf_ptr
;
423 memcpy(buf
, s
->buf_ptr
, len
);
428 unsigned int get_le16(ByteIOContext
*s
)
432 val
|= get_byte(s
) << 8;
436 unsigned int get_le24(ByteIOContext
*s
)
440 val
|= get_byte(s
) << 16;
444 unsigned int get_le32(ByteIOContext
*s
)
448 val
|= get_le16(s
) << 16;
452 uint64_t get_le64(ByteIOContext
*s
)
455 val
= (uint64_t)get_le32(s
);
456 val
|= (uint64_t)get_le32(s
) << 32;
460 unsigned int get_be16(ByteIOContext
*s
)
463 val
= get_byte(s
) << 8;
468 unsigned int get_be24(ByteIOContext
*s
)
471 val
= get_be16(s
) << 8;
475 unsigned int get_be32(ByteIOContext
*s
)
478 val
= get_be16(s
) << 16;
483 char *get_strz(ByteIOContext
*s
, char *buf
, int maxlen
)
488 while ((c
= get_byte(s
))) {
493 buf
[i
] = 0; /* Ensure null terminated, but may be truncated */
498 uint64_t get_be64(ByteIOContext
*s
)
501 val
= (uint64_t)get_be32(s
) << 32;
502 val
|= (uint64_t)get_be32(s
);
506 uint64_t ff_get_v(ByteIOContext
*bc
){
512 val
= (val
<<7) + (tmp
&127);
517 int url_fdopen(ByteIOContext
**s
, URLContext
*h
)
520 int buffer_size
, max_packet_size
;
523 max_packet_size
= url_get_max_packet_size(h
);
524 if (max_packet_size
) {
525 buffer_size
= max_packet_size
; /* no need to bufferize more than one packet */
527 buffer_size
= IO_BUFFER_SIZE
;
529 buffer
= av_malloc(buffer_size
);
531 return AVERROR(ENOMEM
);
533 *s
= av_mallocz(sizeof(ByteIOContext
));
536 return AVERROR(ENOMEM
);
539 if (init_put_byte(*s
, buffer
, buffer_size
,
540 (h
->flags
& URL_WRONLY
|| h
->flags
& URL_RDWR
), h
,
541 url_read
, url_write
, url_seek
) < 0) {
546 (*s
)->is_streamed
= h
->is_streamed
;
547 (*s
)->max_packet_size
= max_packet_size
;
549 (*s
)->read_pause
= (int (*)(void *, int))h
->prot
->url_read_pause
;
550 (*s
)->read_seek
= (offset_t (*)(void *, int, int64_t, int))h
->prot
->url_read_seek
;
555 int url_setbufsize(ByteIOContext
*s
, int buf_size
)
558 buffer
= av_malloc(buf_size
);
560 return AVERROR(ENOMEM
);
564 s
->buffer_size
= buf_size
;
566 url_resetbuf(s
, s
->write_flag
? URL_WRONLY
: URL_RDONLY
);
570 int url_resetbuf(ByteIOContext
*s
, int flags
)
572 URLContext
*h
= s
->opaque
;
573 if ((flags
& URL_RDWR
) || (h
&& h
->flags
!= flags
&& !h
->flags
& URL_RDWR
))
574 return AVERROR(EINVAL
);
576 if (flags
& URL_WRONLY
) {
577 s
->buf_end
= s
->buffer
+ s
->buffer_size
;
580 s
->buf_end
= s
->buffer
;
586 int url_fopen(ByteIOContext
**s
, const char *filename
, int flags
)
591 err
= url_open(&h
, filename
, flags
);
594 err
= url_fdopen(s
, h
);
602 int url_fclose(ByteIOContext
*s
)
604 URLContext
*h
= s
->opaque
;
611 URLContext
*url_fileno(ByteIOContext
*s
)
617 int url_fprintf(ByteIOContext
*s
, const char *fmt
, ...)
624 ret
= vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
626 put_buffer(s
, buf
, strlen(buf
));
629 #endif //CONFIG_MUXERS
631 char *url_fgets(ByteIOContext
*s
, char *buf
, int buf_size
)
641 if (c
== EOF
|| c
== '\n')
643 if ((q
- buf
) < buf_size
- 1)
652 int url_fget_max_packet_size(ByteIOContext
*s
)
654 return s
->max_packet_size
;
657 int av_url_read_fpause(ByteIOContext
*s
, int pause
)
660 return AVERROR(ENOSYS
);
661 return s
->read_pause(s
->opaque
, pause
);
664 offset_t
av_url_read_fseek(ByteIOContext
*s
,
665 int stream_index
, int64_t timestamp
, int flags
)
667 URLContext
*h
= s
->opaque
;
670 return AVERROR(ENOSYS
);
671 ret
= s
->read_seek(h
, stream_index
, timestamp
, flags
);
673 s
->buf_ptr
= s
->buf_end
; // Flush buffer
674 s
->pos
= s
->seek(h
, 0, SEEK_CUR
);
679 /* url_open_dyn_buf and url_close_dyn_buf are used in rtp.c to send a response
680 * back to the server even if CONFIG_MUXERS is not set. */
681 #if defined(CONFIG_MUXERS) || defined(CONFIG_NETWORK)
682 /* buffer handling */
683 int url_open_buf(ByteIOContext
**s
, uint8_t *buf
, int buf_size
, int flags
)
686 *s
= av_mallocz(sizeof(ByteIOContext
));
688 return AVERROR(ENOMEM
);
689 ret
= init_put_byte(*s
, buf
, buf_size
,
690 (flags
& URL_WRONLY
|| flags
& URL_RDWR
),
691 NULL
, NULL
, NULL
, NULL
);
697 int url_close_buf(ByteIOContext
*s
)
700 return s
->buf_ptr
- s
->buffer
;
703 /* output in a dynamic buffer */
705 typedef struct DynBuffer
{
706 int pos
, size
, allocated_size
;
709 uint8_t io_buffer
[1];
712 static int dyn_buf_write(void *opaque
, uint8_t *buf
, int buf_size
)
714 DynBuffer
*d
= opaque
;
715 int new_size
, new_allocated_size
;
717 /* reallocate buffer if needed */
718 new_size
= d
->pos
+ buf_size
;
719 new_allocated_size
= d
->allocated_size
;
720 if(new_size
< d
->pos
|| new_size
> INT_MAX
/2)
722 while (new_size
> new_allocated_size
) {
723 if (!new_allocated_size
)
724 new_allocated_size
= new_size
;
726 new_allocated_size
+= new_allocated_size
/ 2 + 1;
729 if (new_allocated_size
> d
->allocated_size
) {
730 d
->buffer
= av_realloc(d
->buffer
, new_allocated_size
);
731 if(d
->buffer
== NULL
)
733 d
->allocated_size
= new_allocated_size
;
735 memcpy(d
->buffer
+ d
->pos
, buf
, buf_size
);
737 if (d
->pos
> d
->size
)
742 static int dyn_packet_buf_write(void *opaque
, uint8_t *buf
, int buf_size
)
744 unsigned char buf1
[4];
747 /* packetized write: output the header */
748 buf1
[0] = (buf_size
>> 24);
749 buf1
[1] = (buf_size
>> 16);
750 buf1
[2] = (buf_size
>> 8);
751 buf1
[3] = (buf_size
);
752 ret
= dyn_buf_write(opaque
, buf1
, 4);
757 return dyn_buf_write(opaque
, buf
, buf_size
);
760 static offset_t
dyn_buf_seek(void *opaque
, offset_t offset
, int whence
)
762 DynBuffer
*d
= opaque
;
764 if (whence
== SEEK_CUR
)
766 else if (whence
== SEEK_END
)
768 if (offset
< 0 || offset
> 0x7fffffffLL
)
774 static int url_open_dyn_buf_internal(ByteIOContext
**s
, int max_packet_size
)
777 int io_buffer_size
, ret
;
780 io_buffer_size
= max_packet_size
;
782 io_buffer_size
= 1024;
784 if(sizeof(DynBuffer
) + io_buffer_size
< io_buffer_size
)
786 d
= av_malloc(sizeof(DynBuffer
) + io_buffer_size
);
789 *s
= av_mallocz(sizeof(ByteIOContext
));
792 return AVERROR(ENOMEM
);
794 d
->io_buffer_size
= io_buffer_size
;
798 d
->allocated_size
= 0;
799 ret
= init_put_byte(*s
, d
->io_buffer
, io_buffer_size
,
801 max_packet_size
? dyn_packet_buf_write
: dyn_buf_write
,
802 max_packet_size
? NULL
: dyn_buf_seek
);
804 (*s
)->max_packet_size
= max_packet_size
;
812 int url_open_dyn_buf(ByteIOContext
**s
)
814 return url_open_dyn_buf_internal(s
, 0);
817 int url_open_dyn_packet_buf(ByteIOContext
**s
, int max_packet_size
)
819 if (max_packet_size
<= 0)
821 return url_open_dyn_buf_internal(s
, max_packet_size
);
824 int url_close_dyn_buf(ByteIOContext
*s
, uint8_t **pbuffer
)
826 DynBuffer
*d
= s
->opaque
;
831 *pbuffer
= d
->buffer
;
837 #endif /* CONFIG_MUXERS || CONFIG_NETWORK */