blob: ef6a0d4e9ba3d17a4fe554bbeb7f9d3b2f519c51
1 | /* |
2 | * buffered I/O |
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/bprint.h" |
23 | #include "libavutil/crc.h" |
24 | #include "libavutil/dict.h" |
25 | #include "libavutil/intreadwrite.h" |
26 | #include "libavutil/log.h" |
27 | #include "libavutil/opt.h" |
28 | #include "libavutil/avassert.h" |
29 | #include "avformat.h" |
30 | #include "avio.h" |
31 | #include "avio_internal.h" |
32 | #include "internal.h" |
33 | #include "url.h" |
34 | #include <stdarg.h> |
35 | |
36 | #define IO_BUFFER_SIZE 32768 |
37 | |
38 | /** |
39 | * Do seeks within this distance ahead of the current buffer by skipping |
40 | * data instead of calling the protocol seek function, for seekable |
41 | * protocols. |
42 | */ |
43 | #define SHORT_SEEK_THRESHOLD 4096 |
44 | |
45 | typedef struct AVIOInternal { |
46 | URLContext *h; |
47 | } AVIOInternal; |
48 | |
49 | static void *ff_avio_child_next(void *obj, void *prev) |
50 | { |
51 | AVIOContext *s = obj; |
52 | AVIOInternal *internal = s->opaque; |
53 | return prev ? NULL : internal->h; |
54 | } |
55 | |
56 | static const AVClass *ff_avio_child_class_next(const AVClass *prev) |
57 | { |
58 | return prev ? NULL : &ffurl_context_class; |
59 | } |
60 | |
61 | #define OFFSET(x) offsetof(AVIOContext,x) |
62 | #define E AV_OPT_FLAG_ENCODING_PARAM |
63 | #define D AV_OPT_FLAG_DECODING_PARAM |
64 | static const AVOption ff_avio_options[] = { |
65 | {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, |
66 | { NULL }, |
67 | }; |
68 | |
69 | const AVClass ff_avio_class = { |
70 | .class_name = "AVIOContext", |
71 | .item_name = av_default_item_name, |
72 | .version = LIBAVUTIL_VERSION_INT, |
73 | .option = ff_avio_options, |
74 | .child_next = ff_avio_child_next, |
75 | .child_class_next = ff_avio_child_class_next, |
76 | }; |
77 | |
78 | static void fill_buffer(AVIOContext *s); |
79 | static int url_resetbuf(AVIOContext *s, int flags); |
80 | |
81 | int ffio_init_context(AVIOContext *s, |
82 | unsigned char *buffer, |
83 | int buffer_size, |
84 | int write_flag, |
85 | void *opaque, |
86 | int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), |
87 | int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), |
88 | int64_t (*seek)(void *opaque, int64_t offset, int whence)) |
89 | { |
90 | s->buffer = buffer; |
91 | s->orig_buffer_size = |
92 | s->buffer_size = buffer_size; |
93 | s->buf_ptr = buffer; |
94 | s->opaque = opaque; |
95 | s->direct = 0; |
96 | |
97 | url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); |
98 | |
99 | s->write_packet = write_packet; |
100 | s->read_packet = read_packet; |
101 | s->seek = seek; |
102 | s->pos = 0; |
103 | s->must_flush = 0; |
104 | s->eof_reached = 0; |
105 | s->error = 0; |
106 | s->seekable = seek ? AVIO_SEEKABLE_NORMAL : 0; |
107 | s->max_packet_size = 0; |
108 | s->update_checksum = NULL; |
109 | s->short_seek_threshold = SHORT_SEEK_THRESHOLD; |
110 | |
111 | if (!read_packet && !write_flag) { |
112 | s->pos = buffer_size; |
113 | s->buf_end = s->buffer + buffer_size; |
114 | } |
115 | s->read_pause = NULL; |
116 | s->read_seek = NULL; |
117 | |
118 | s->write_data_type = NULL; |
119 | s->ignore_boundary_point = 0; |
120 | s->current_type = AVIO_DATA_MARKER_UNKNOWN; |
121 | s->last_time = AV_NOPTS_VALUE; |
122 | s->short_seek_get = NULL; |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | AVIOContext *avio_alloc_context( |
128 | unsigned char *buffer, |
129 | int buffer_size, |
130 | int write_flag, |
131 | void *opaque, |
132 | int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), |
133 | int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), |
134 | int64_t (*seek)(void *opaque, int64_t offset, int whence)) |
135 | { |
136 | AVIOContext *s = av_mallocz(sizeof(AVIOContext)); |
137 | if (!s) |
138 | return NULL; |
139 | ffio_init_context(s, buffer, buffer_size, write_flag, opaque, |
140 | read_packet, write_packet, seek); |
141 | return s; |
142 | } |
143 | |
144 | static void writeout(AVIOContext *s, const uint8_t *data, int len) |
145 | { |
146 | if (!s->error) { |
147 | int ret = 0; |
148 | if (s->write_data_type) |
149 | ret = s->write_data_type(s->opaque, (uint8_t *)data, |
150 | len, |
151 | s->current_type, |
152 | s->last_time); |
153 | else if (s->write_packet) |
154 | ret = s->write_packet(s->opaque, (uint8_t *)data, len); |
155 | if (ret < 0) { |
156 | s->error = ret; |
157 | } |
158 | } |
159 | if (s->current_type == AVIO_DATA_MARKER_SYNC_POINT || |
160 | s->current_type == AVIO_DATA_MARKER_BOUNDARY_POINT) { |
161 | s->current_type = AVIO_DATA_MARKER_UNKNOWN; |
162 | } |
163 | s->last_time = AV_NOPTS_VALUE; |
164 | s->writeout_count ++; |
165 | s->pos += len; |
166 | } |
167 | |
168 | static void flush_buffer(AVIOContext *s) |
169 | { |
170 | if (s->write_flag && s->buf_ptr > s->buffer) { |
171 | writeout(s, s->buffer, s->buf_ptr - s->buffer); |
172 | if (s->update_checksum) { |
173 | s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, |
174 | s->buf_ptr - s->checksum_ptr); |
175 | s->checksum_ptr = s->buffer; |
176 | } |
177 | } |
178 | s->buf_ptr = s->buffer; |
179 | if (!s->write_flag) |
180 | s->buf_end = s->buffer; |
181 | } |
182 | |
183 | void avio_w8(AVIOContext *s, int b) |
184 | { |
185 | av_assert2(b>=-128 && b<=255); |
186 | *s->buf_ptr++ = b; |
187 | if (s->buf_ptr >= s->buf_end) |
188 | flush_buffer(s); |
189 | } |
190 | |
191 | void ffio_fill(AVIOContext *s, int b, int count) |
192 | { |
193 | while (count > 0) { |
194 | int len = FFMIN(s->buf_end - s->buf_ptr, count); |
195 | memset(s->buf_ptr, b, len); |
196 | s->buf_ptr += len; |
197 | |
198 | if (s->buf_ptr >= s->buf_end) |
199 | flush_buffer(s); |
200 | |
201 | count -= len; |
202 | } |
203 | } |
204 | |
205 | void avio_write(AVIOContext *s, const unsigned char *buf, int size) |
206 | { |
207 | if (s->direct && !s->update_checksum) { |
208 | avio_flush(s); |
209 | writeout(s, buf, size); |
210 | return; |
211 | } |
212 | while (size > 0) { |
213 | int len = FFMIN(s->buf_end - s->buf_ptr, size); |
214 | memcpy(s->buf_ptr, buf, len); |
215 | s->buf_ptr += len; |
216 | |
217 | if (s->buf_ptr >= s->buf_end) |
218 | flush_buffer(s); |
219 | |
220 | buf += len; |
221 | size -= len; |
222 | } |
223 | } |
224 | |
225 | void avio_flush(AVIOContext *s) |
226 | { |
227 | flush_buffer(s); |
228 | s->must_flush = 0; |
229 | } |
230 | |
231 | int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) |
232 | { |
233 | int64_t offset1; |
234 | int64_t pos; |
235 | int force = whence & AVSEEK_FORCE; |
236 | int buffer_size; |
237 | int short_seek; |
238 | whence &= ~AVSEEK_FORCE; |
239 | |
240 | if(!s) |
241 | return AVERROR(EINVAL); |
242 | |
243 | buffer_size = s->buf_end - s->buffer; |
244 | // pos is the absolute position that the beginning of s->buffer corresponds to in the file |
245 | pos = s->pos - (s->write_flag ? 0 : buffer_size); |
246 | |
247 | if (whence != SEEK_CUR && whence != SEEK_SET) |
248 | return AVERROR(EINVAL); |
249 | |
250 | if (whence == SEEK_CUR) { |
251 | offset1 = pos + (s->buf_ptr - s->buffer); |
252 | if (offset == 0) |
253 | return offset1; |
254 | offset += offset1; |
255 | } |
256 | if (offset < 0) |
257 | return AVERROR(EINVAL); |
258 | |
259 | if (s->short_seek_get) { |
260 | short_seek = s->short_seek_get(s->opaque); |
261 | /* fallback to default short seek */ |
262 | if (short_seek <= 0) |
263 | short_seek = s->short_seek_threshold; |
264 | } else |
265 | short_seek = s->short_seek_threshold; |
266 | |
267 | offset1 = offset - pos; // "offset1" is the relative offset from the beginning of s->buffer |
268 | if (!s->must_flush && (!s->direct || !s->seek) && |
269 | offset1 >= 0 && offset1 <= buffer_size - s->write_flag) { |
270 | /* can do the seek inside the buffer */ |
271 | s->buf_ptr = s->buffer + offset1; |
272 | } else if ((!(s->seekable & AVIO_SEEKABLE_NORMAL) || |
273 | offset1 <= buffer_size + short_seek) && |
274 | !s->write_flag && offset1 >= 0 && |
275 | (!s->direct || !s->seek) && |
276 | (whence != SEEK_END || force)) { |
277 | while(s->pos < offset && !s->eof_reached) |
278 | fill_buffer(s); |
279 | if (s->eof_reached) |
280 | return AVERROR_EOF; |
281 | s->buf_ptr = s->buf_end - (s->pos - offset); |
282 | } else if(!s->write_flag && offset1 < 0 && -offset1 < buffer_size>>1 && s->seek && offset > 0) { |
283 | int64_t res; |
284 | |
285 | pos -= FFMIN(buffer_size>>1, pos); |
286 | if ((res = s->seek(s->opaque, pos, SEEK_SET)) < 0) |
287 | return res; |
288 | s->buf_end = |
289 | s->buf_ptr = s->buffer; |
290 | s->pos = pos; |
291 | s->eof_reached = 0; |
292 | fill_buffer(s); |
293 | return avio_seek(s, offset, SEEK_SET | force); |
294 | } else { |
295 | int64_t res; |
296 | if (s->write_flag) { |
297 | flush_buffer(s); |
298 | s->must_flush = 1; |
299 | } |
300 | if (!s->seek) |
301 | return AVERROR(EPIPE); |
302 | if ((res = s->seek(s->opaque, offset, SEEK_SET)) < 0) |
303 | return res; |
304 | s->seek_count ++; |
305 | if (!s->write_flag) |
306 | s->buf_end = s->buffer; |
307 | s->buf_ptr = s->buffer; |
308 | s->pos = offset; |
309 | } |
310 | s->eof_reached = 0; |
311 | return offset; |
312 | } |
313 | |
314 | int64_t avio_skip(AVIOContext *s, int64_t offset) |
315 | { |
316 | return avio_seek(s, offset, SEEK_CUR); |
317 | } |
318 | |
319 | int64_t avio_size(AVIOContext *s) |
320 | { |
321 | int64_t size; |
322 | |
323 | if (!s) |
324 | return AVERROR(EINVAL); |
325 | |
326 | if (!s->seek) |
327 | return AVERROR(ENOSYS); |
328 | size = s->seek(s->opaque, 0, AVSEEK_SIZE); |
329 | if (size < 0) { |
330 | if ((size = s->seek(s->opaque, -1, SEEK_END)) < 0) |
331 | return size; |
332 | size++; |
333 | s->seek(s->opaque, s->pos, SEEK_SET); |
334 | } |
335 | return size; |
336 | } |
337 | |
338 | int avio_feof(AVIOContext *s) |
339 | { |
340 | if(!s) |
341 | return 0; |
342 | if(s->eof_reached){ |
343 | s->eof_reached=0; |
344 | fill_buffer(s); |
345 | } |
346 | return s->eof_reached; |
347 | } |
348 | |
349 | #if FF_API_URL_FEOF |
350 | int url_feof(AVIOContext *s) |
351 | { |
352 | return avio_feof(s); |
353 | } |
354 | #endif |
355 | |
356 | void avio_wl32(AVIOContext *s, unsigned int val) |
357 | { |
358 | avio_w8(s, (uint8_t) val ); |
359 | avio_w8(s, (uint8_t)(val >> 8 )); |
360 | avio_w8(s, (uint8_t)(val >> 16)); |
361 | avio_w8(s, val >> 24 ); |
362 | } |
363 | |
364 | void avio_wb32(AVIOContext *s, unsigned int val) |
365 | { |
366 | avio_w8(s, val >> 24 ); |
367 | avio_w8(s, (uint8_t)(val >> 16)); |
368 | avio_w8(s, (uint8_t)(val >> 8 )); |
369 | avio_w8(s, (uint8_t) val ); |
370 | } |
371 | |
372 | int avio_put_str(AVIOContext *s, const char *str) |
373 | { |
374 | int len = 1; |
375 | if (str) { |
376 | len += strlen(str); |
377 | avio_write(s, (const unsigned char *) str, len); |
378 | } else |
379 | avio_w8(s, 0); |
380 | return len; |
381 | } |
382 | |
383 | static inline int put_str16(AVIOContext *s, const char *str, const int be) |
384 | { |
385 | const uint8_t *q = str; |
386 | int ret = 0; |
387 | int err = 0; |
388 | |
389 | while (*q) { |
390 | uint32_t ch; |
391 | uint16_t tmp; |
392 | |
393 | GET_UTF8(ch, *q++, goto invalid;) |
394 | PUT_UTF16(ch, tmp, be ? avio_wb16(s, tmp) : avio_wl16(s, tmp); |
395 | ret += 2;) |
396 | continue; |
397 | invalid: |
398 | av_log(s, AV_LOG_ERROR, "Invalid UTF8 sequence in avio_put_str16%s\n", be ? "be" : "le"); |
399 | err = AVERROR(EINVAL); |
400 | if (!*(q-1)) |
401 | break; |
402 | } |
403 | if (be) |
404 | avio_wb16(s, 0); |
405 | else |
406 | avio_wl16(s, 0); |
407 | if (err) |
408 | return err; |
409 | ret += 2; |
410 | return ret; |
411 | } |
412 | |
413 | #define PUT_STR16(type, big_endian) \ |
414 | int avio_put_str16 ## type(AVIOContext *s, const char *str) \ |
415 | { \ |
416 | return put_str16(s, str, big_endian); \ |
417 | } |
418 | |
419 | PUT_STR16(le, 0) |
420 | PUT_STR16(be, 1) |
421 | |
422 | #undef PUT_STR16 |
423 | |
424 | int ff_get_v_length(uint64_t val) |
425 | { |
426 | int i = 1; |
427 | |
428 | while (val >>= 7) |
429 | i++; |
430 | |
431 | return i; |
432 | } |
433 | |
434 | void ff_put_v(AVIOContext *bc, uint64_t val) |
435 | { |
436 | int i = ff_get_v_length(val); |
437 | |
438 | while (--i > 0) |
439 | avio_w8(bc, 128 | (uint8_t)(val >> (7*i))); |
440 | |
441 | avio_w8(bc, val & 127); |
442 | } |
443 | |
444 | void avio_wl64(AVIOContext *s, uint64_t val) |
445 | { |
446 | avio_wl32(s, (uint32_t)(val & 0xffffffff)); |
447 | avio_wl32(s, (uint32_t)(val >> 32)); |
448 | } |
449 | |
450 | void avio_wb64(AVIOContext *s, uint64_t val) |
451 | { |
452 | avio_wb32(s, (uint32_t)(val >> 32)); |
453 | avio_wb32(s, (uint32_t)(val & 0xffffffff)); |
454 | } |
455 | |
456 | void avio_wl16(AVIOContext *s, unsigned int val) |
457 | { |
458 | avio_w8(s, (uint8_t)val); |
459 | avio_w8(s, (int)val >> 8); |
460 | } |
461 | |
462 | void avio_wb16(AVIOContext *s, unsigned int val) |
463 | { |
464 | avio_w8(s, (int)val >> 8); |
465 | avio_w8(s, (uint8_t)val); |
466 | } |
467 | |
468 | void avio_wl24(AVIOContext *s, unsigned int val) |
469 | { |
470 | avio_wl16(s, val & 0xffff); |
471 | avio_w8(s, (int)val >> 16); |
472 | } |
473 | |
474 | void avio_wb24(AVIOContext *s, unsigned int val) |
475 | { |
476 | avio_wb16(s, (int)val >> 8); |
477 | avio_w8(s, (uint8_t)val); |
478 | } |
479 | |
480 | void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type) |
481 | { |
482 | if (!s->write_data_type) |
483 | return; |
484 | // If ignoring boundary points, just treat it as unknown |
485 | if (type == AVIO_DATA_MARKER_BOUNDARY_POINT && s->ignore_boundary_point) |
486 | type = AVIO_DATA_MARKER_UNKNOWN; |
487 | // Avoid unnecessary flushes if we are already in non-header/trailer |
488 | // data and setting the type to unknown |
489 | if (type == AVIO_DATA_MARKER_UNKNOWN && |
490 | (s->current_type != AVIO_DATA_MARKER_HEADER && |
491 | s->current_type != AVIO_DATA_MARKER_TRAILER)) |
492 | return; |
493 | |
494 | switch (type) { |
495 | case AVIO_DATA_MARKER_HEADER: |
496 | case AVIO_DATA_MARKER_TRAILER: |
497 | // For header/trailer, ignore a new marker of the same type; |
498 | // consecutive header/trailer markers can be merged. |
499 | if (type == s->current_type) |
500 | return; |
501 | break; |
502 | } |
503 | |
504 | // If we've reached here, we have a new, noteworthy marker. |
505 | // Flush the previous data and mark the start of the new data. |
506 | avio_flush(s); |
507 | s->current_type = type; |
508 | s->last_time = time; |
509 | } |
510 | |
511 | /* Input stream */ |
512 | |
513 | static void fill_buffer(AVIOContext *s) |
514 | { |
515 | int max_buffer_size = s->max_packet_size ? |
516 | s->max_packet_size : IO_BUFFER_SIZE; |
517 | uint8_t *dst = s->buf_end - s->buffer + max_buffer_size < s->buffer_size ? |
518 | s->buf_end : s->buffer; |
519 | int len = s->buffer_size - (dst - s->buffer); |
520 | |
521 | /* can't fill the buffer without read_packet, just set EOF if appropriate */ |
522 | if (!s->read_packet && s->buf_ptr >= s->buf_end) |
523 | s->eof_reached = 1; |
524 | |
525 | /* no need to do anything if EOF already reached */ |
526 | if (s->eof_reached) |
527 | return; |
528 | |
529 | if (s->update_checksum && dst == s->buffer) { |
530 | if (s->buf_end > s->checksum_ptr) |
531 | s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, |
532 | s->buf_end - s->checksum_ptr); |
533 | s->checksum_ptr = s->buffer; |
534 | } |
535 | |
536 | /* make buffer smaller in case it ended up large after probing */ |
537 | if (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size) { |
538 | if (dst == s->buffer) { |
539 | int ret = ffio_set_buf_size(s, s->orig_buffer_size); |
540 | if (ret < 0) |
541 | av_log(s, AV_LOG_WARNING, "Failed to decrease buffer size\n"); |
542 | |
543 | s->checksum_ptr = dst = s->buffer; |
544 | } |
545 | av_assert0(len >= s->orig_buffer_size); |
546 | len = s->orig_buffer_size; |
547 | } |
548 | |
549 | if (s->read_packet) |
550 | len = s->read_packet(s->opaque, dst, len); |
551 | else |
552 | len = 0; |
553 | if (len <= 0) { |
554 | /* do not modify buffer if EOF reached so that a seek back can |
555 | be done without rereading data */ |
556 | s->eof_reached = 1; |
557 | if (len < 0) |
558 | s->error = len; |
559 | } else { |
560 | s->pos += len; |
561 | s->buf_ptr = dst; |
562 | s->buf_end = dst + len; |
563 | s->bytes_read += len; |
564 | } |
565 | } |
566 | |
567 | unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, |
568 | unsigned int len) |
569 | { |
570 | return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf, len); |
571 | } |
572 | |
573 | unsigned long ff_crcEDB88320_update(unsigned long checksum, const uint8_t *buf, |
574 | unsigned int len) |
575 | { |
576 | return av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), checksum, buf, len); |
577 | } |
578 | |
579 | unsigned long ff_crcA001_update(unsigned long checksum, const uint8_t *buf, |
580 | unsigned int len) |
581 | { |
582 | return av_crc(av_crc_get_table(AV_CRC_16_ANSI_LE), checksum, buf, len); |
583 | } |
584 | |
585 | unsigned long ffio_get_checksum(AVIOContext *s) |
586 | { |
587 | s->checksum = s->update_checksum(s->checksum, s->checksum_ptr, |
588 | s->buf_ptr - s->checksum_ptr); |
589 | s->update_checksum = NULL; |
590 | return s->checksum; |
591 | } |
592 | |
593 | void ffio_init_checksum(AVIOContext *s, |
594 | unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), |
595 | unsigned long checksum) |
596 | { |
597 | s->update_checksum = update_checksum; |
598 | if (s->update_checksum) { |
599 | s->checksum = checksum; |
600 | s->checksum_ptr = s->buf_ptr; |
601 | } |
602 | } |
603 | |
604 | /* XXX: put an inline version */ |
605 | int avio_r8(AVIOContext *s) |
606 | { |
607 | if (s->buf_ptr >= s->buf_end) |
608 | fill_buffer(s); |
609 | if (s->buf_ptr < s->buf_end) |
610 | return *s->buf_ptr++; |
611 | return 0; |
612 | } |
613 | |
614 | int avio_read(AVIOContext *s, unsigned char *buf, int size) |
615 | { |
616 | int len, size1; |
617 | |
618 | size1 = size; |
619 | while (size > 0) { |
620 | len = FFMIN(s->buf_end - s->buf_ptr, size); |
621 | if (len == 0 || s->write_flag) { |
622 | if((s->direct || size > s->buffer_size) && !s->update_checksum) { |
623 | // bypass the buffer and read data directly into buf |
624 | if(s->read_packet) |
625 | len = s->read_packet(s->opaque, buf, size); |
626 | |
627 | if (len <= 0) { |
628 | /* do not modify buffer if EOF reached so that a seek back can |
629 | be done without rereading data */ |
630 | s->eof_reached = 1; |
631 | if(len<0) |
632 | s->error= len; |
633 | break; |
634 | } else { |
635 | s->pos += len; |
636 | s->bytes_read += len; |
637 | size -= len; |
638 | buf += len; |
639 | // reset the buffer |
640 | s->buf_ptr = s->buffer; |
641 | s->buf_end = s->buffer/* + len*/; |
642 | } |
643 | } else { |
644 | fill_buffer(s); |
645 | len = s->buf_end - s->buf_ptr; |
646 | if (len == 0) |
647 | break; |
648 | } |
649 | } else { |
650 | memcpy(buf, s->buf_ptr, len); |
651 | buf += len; |
652 | s->buf_ptr += len; |
653 | size -= len; |
654 | } |
655 | } |
656 | if (size1 == size) { |
657 | if (s->error) return s->error; |
658 | if (avio_feof(s)) return AVERROR_EOF; |
659 | } |
660 | return size1 - size; |
661 | } |
662 | |
663 | int ffio_read_size(AVIOContext *s, unsigned char *buf, int size) |
664 | { |
665 | int ret = avio_read(s, buf, size); |
666 | if (ret != size) |
667 | return AVERROR_INVALIDDATA; |
668 | return ret; |
669 | } |
670 | |
671 | int ffio_read_indirect(AVIOContext *s, unsigned char *buf, int size, const unsigned char **data) |
672 | { |
673 | if (s->buf_end - s->buf_ptr >= size && !s->write_flag) { |
674 | *data = s->buf_ptr; |
675 | s->buf_ptr += size; |
676 | return size; |
677 | } else { |
678 | *data = buf; |
679 | return avio_read(s, buf, size); |
680 | } |
681 | } |
682 | |
683 | int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size) |
684 | { |
685 | int len; |
686 | |
687 | if (size < 0) |
688 | return -1; |
689 | |
690 | if (s->read_packet && s->write_flag) { |
691 | len = s->read_packet(s->opaque, buf, size); |
692 | if (len > 0) |
693 | s->pos += len; |
694 | return len; |
695 | } |
696 | |
697 | len = s->buf_end - s->buf_ptr; |
698 | if (len == 0) { |
699 | /* Reset the buf_end pointer to the start of the buffer, to make sure |
700 | * the fill_buffer call tries to read as much data as fits into the |
701 | * full buffer, instead of just what space is left after buf_end. |
702 | * This avoids returning partial packets at the end of the buffer, |
703 | * for packet based inputs. |
704 | */ |
705 | s->buf_end = s->buf_ptr = s->buffer; |
706 | fill_buffer(s); |
707 | len = s->buf_end - s->buf_ptr; |
708 | } |
709 | if (len > size) |
710 | len = size; |
711 | memcpy(buf, s->buf_ptr, len); |
712 | s->buf_ptr += len; |
713 | if (!len) { |
714 | if (s->error) return s->error; |
715 | if (avio_feof(s)) return AVERROR_EOF; |
716 | } |
717 | return len; |
718 | } |
719 | |
720 | unsigned int avio_rl16(AVIOContext *s) |
721 | { |
722 | unsigned int val; |
723 | val = avio_r8(s); |
724 | val |= avio_r8(s) << 8; |
725 | return val; |
726 | } |
727 | |
728 | unsigned int avio_rl24(AVIOContext *s) |
729 | { |
730 | unsigned int val; |
731 | val = avio_rl16(s); |
732 | val |= avio_r8(s) << 16; |
733 | return val; |
734 | } |
735 | |
736 | unsigned int avio_rl32(AVIOContext *s) |
737 | { |
738 | unsigned int val; |
739 | val = avio_rl16(s); |
740 | val |= avio_rl16(s) << 16; |
741 | return val; |
742 | } |
743 | |
744 | uint64_t avio_rl64(AVIOContext *s) |
745 | { |
746 | uint64_t val; |
747 | val = (uint64_t)avio_rl32(s); |
748 | val |= (uint64_t)avio_rl32(s) << 32; |
749 | return val; |
750 | } |
751 | |
752 | unsigned int avio_rb16(AVIOContext *s) |
753 | { |
754 | unsigned int val; |
755 | val = avio_r8(s) << 8; |
756 | val |= avio_r8(s); |
757 | return val; |
758 | } |
759 | |
760 | unsigned int avio_rb24(AVIOContext *s) |
761 | { |
762 | unsigned int val; |
763 | val = avio_rb16(s) << 8; |
764 | val |= avio_r8(s); |
765 | return val; |
766 | } |
767 | unsigned int avio_rb32(AVIOContext *s) |
768 | { |
769 | unsigned int val; |
770 | val = avio_rb16(s) << 16; |
771 | val |= avio_rb16(s); |
772 | return val; |
773 | } |
774 | |
775 | int ff_get_line(AVIOContext *s, char *buf, int maxlen) |
776 | { |
777 | int i = 0; |
778 | char c; |
779 | |
780 | do { |
781 | c = avio_r8(s); |
782 | if (c && i < maxlen-1) |
783 | buf[i++] = c; |
784 | } while (c != '\n' && c != '\r' && c); |
785 | if (c == '\r' && avio_r8(s) != '\n' && !avio_feof(s)) |
786 | avio_skip(s, -1); |
787 | |
788 | buf[i] = 0; |
789 | return i; |
790 | } |
791 | |
792 | int avio_get_str(AVIOContext *s, int maxlen, char *buf, int buflen) |
793 | { |
794 | int i; |
795 | |
796 | if (buflen <= 0) |
797 | return AVERROR(EINVAL); |
798 | // reserve 1 byte for terminating 0 |
799 | buflen = FFMIN(buflen - 1, maxlen); |
800 | for (i = 0; i < buflen; i++) |
801 | if (!(buf[i] = avio_r8(s))) |
802 | return i + 1; |
803 | buf[i] = 0; |
804 | for (; i < maxlen; i++) |
805 | if (!avio_r8(s)) |
806 | return i + 1; |
807 | return maxlen; |
808 | } |
809 | |
810 | #define GET_STR16(type, read) \ |
811 | int avio_get_str16 ##type(AVIOContext *pb, int maxlen, char *buf, int buflen)\ |
812 | {\ |
813 | char* q = buf;\ |
814 | int ret = 0;\ |
815 | if (buflen <= 0) \ |
816 | return AVERROR(EINVAL); \ |
817 | while (ret + 1 < maxlen) {\ |
818 | uint8_t tmp;\ |
819 | uint32_t ch;\ |
820 | GET_UTF16(ch, (ret += 2) <= maxlen ? read(pb) : 0, break;)\ |
821 | if (!ch)\ |
822 | break;\ |
823 | PUT_UTF8(ch, tmp, if (q - buf < buflen - 1) *q++ = tmp;)\ |
824 | }\ |
825 | *q = 0;\ |
826 | return ret;\ |
827 | }\ |
828 | |
829 | GET_STR16(le, avio_rl16) |
830 | GET_STR16(be, avio_rb16) |
831 | |
832 | #undef GET_STR16 |
833 | |
834 | uint64_t avio_rb64(AVIOContext *s) |
835 | { |
836 | uint64_t val; |
837 | val = (uint64_t)avio_rb32(s) << 32; |
838 | val |= (uint64_t)avio_rb32(s); |
839 | return val; |
840 | } |
841 | |
842 | uint64_t ffio_read_varlen(AVIOContext *bc){ |
843 | uint64_t val = 0; |
844 | int tmp; |
845 | |
846 | do{ |
847 | tmp = avio_r8(bc); |
848 | val= (val<<7) + (tmp&127); |
849 | }while(tmp&128); |
850 | return val; |
851 | } |
852 | |
853 | static int io_read_packet(void *opaque, uint8_t *buf, int buf_size) |
854 | { |
855 | AVIOInternal *internal = opaque; |
856 | return ffurl_read(internal->h, buf, buf_size); |
857 | } |
858 | |
859 | static int io_write_packet(void *opaque, uint8_t *buf, int buf_size) |
860 | { |
861 | AVIOInternal *internal = opaque; |
862 | return ffurl_write(internal->h, buf, buf_size); |
863 | } |
864 | |
865 | static int64_t io_seek(void *opaque, int64_t offset, int whence) |
866 | { |
867 | AVIOInternal *internal = opaque; |
868 | return ffurl_seek(internal->h, offset, whence); |
869 | } |
870 | |
871 | static int io_short_seek(void *opaque) |
872 | { |
873 | AVIOInternal *internal = opaque; |
874 | return ffurl_get_short_seek(internal->h); |
875 | } |
876 | |
877 | static int io_read_pause(void *opaque, int pause) |
878 | { |
879 | AVIOInternal *internal = opaque; |
880 | if (!internal->h->prot->url_read_pause) |
881 | return AVERROR(ENOSYS); |
882 | return internal->h->prot->url_read_pause(internal->h, pause); |
883 | } |
884 | |
885 | static int64_t io_read_seek(void *opaque, int stream_index, int64_t timestamp, int flags) |
886 | { |
887 | AVIOInternal *internal = opaque; |
888 | if (!internal->h->prot->url_read_seek) |
889 | return AVERROR(ENOSYS); |
890 | return internal->h->prot->url_read_seek(internal->h, stream_index, timestamp, flags); |
891 | } |
892 | |
893 | int ffio_fdopen(AVIOContext **s, URLContext *h) |
894 | { |
895 | AVIOInternal *internal = NULL; |
896 | uint8_t *buffer = NULL; |
897 | int buffer_size, max_packet_size; |
898 | |
899 | max_packet_size = h->max_packet_size; |
900 | if (max_packet_size) { |
901 | buffer_size = max_packet_size; /* no need to bufferize more than one packet */ |
902 | } else { |
903 | buffer_size = IO_BUFFER_SIZE; |
904 | } |
905 | buffer = av_malloc(buffer_size); |
906 | if (!buffer) |
907 | return AVERROR(ENOMEM); |
908 | |
909 | internal = av_mallocz(sizeof(*internal)); |
910 | if (!internal) |
911 | goto fail; |
912 | |
913 | internal->h = h; |
914 | |
915 | *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, |
916 | internal, io_read_packet, io_write_packet, io_seek); |
917 | if (!*s) |
918 | goto fail; |
919 | |
920 | (*s)->protocol_whitelist = av_strdup(h->protocol_whitelist); |
921 | if (!(*s)->protocol_whitelist && h->protocol_whitelist) { |
922 | avio_closep(s); |
923 | goto fail; |
924 | } |
925 | (*s)->protocol_blacklist = av_strdup(h->protocol_blacklist); |
926 | if (!(*s)->protocol_blacklist && h->protocol_blacklist) { |
927 | avio_closep(s); |
928 | goto fail; |
929 | } |
930 | (*s)->direct = h->flags & AVIO_FLAG_DIRECT; |
931 | |
932 | (*s)->seekable = h->is_streamed ? 0 : AVIO_SEEKABLE_NORMAL; |
933 | (*s)->max_packet_size = max_packet_size; |
934 | if(h->prot) { |
935 | (*s)->read_pause = io_read_pause; |
936 | (*s)->read_seek = io_read_seek; |
937 | |
938 | if (h->prot->url_read_seek) |
939 | (*s)->seekable |= AVIO_SEEKABLE_TIME; |
940 | } |
941 | (*s)->short_seek_get = io_short_seek; |
942 | (*s)->av_class = &ff_avio_class; |
943 | return 0; |
944 | fail: |
945 | av_freep(&internal); |
946 | av_freep(&buffer); |
947 | return AVERROR(ENOMEM); |
948 | } |
949 | |
950 | int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size) |
951 | { |
952 | uint8_t *buffer; |
953 | int max_buffer_size = s->max_packet_size ? |
954 | s->max_packet_size : IO_BUFFER_SIZE; |
955 | int filled = s->buf_end - s->buffer; |
956 | ptrdiff_t checksum_ptr_offset = s->checksum_ptr ? s->checksum_ptr - s->buffer : -1; |
957 | |
958 | buf_size += s->buf_ptr - s->buffer + max_buffer_size; |
959 | |
960 | if (buf_size < filled || s->seekable || !s->read_packet) |
961 | return 0; |
962 | av_assert0(!s->write_flag); |
963 | |
964 | buffer = av_malloc(buf_size); |
965 | if (!buffer) |
966 | return AVERROR(ENOMEM); |
967 | |
968 | memcpy(buffer, s->buffer, filled); |
969 | av_free(s->buffer); |
970 | s->buf_ptr = buffer + (s->buf_ptr - s->buffer); |
971 | s->buf_end = buffer + (s->buf_end - s->buffer); |
972 | s->buffer = buffer; |
973 | s->buffer_size = buf_size; |
974 | if (checksum_ptr_offset >= 0) |
975 | s->checksum_ptr = s->buffer + checksum_ptr_offset; |
976 | return 0; |
977 | } |
978 | |
979 | int ffio_set_buf_size(AVIOContext *s, int buf_size) |
980 | { |
981 | uint8_t *buffer; |
982 | buffer = av_malloc(buf_size); |
983 | if (!buffer) |
984 | return AVERROR(ENOMEM); |
985 | |
986 | av_free(s->buffer); |
987 | s->buffer = buffer; |
988 | s->orig_buffer_size = |
989 | s->buffer_size = buf_size; |
990 | s->buf_ptr = buffer; |
991 | url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ); |
992 | return 0; |
993 | } |
994 | |
995 | static int url_resetbuf(AVIOContext *s, int flags) |
996 | { |
997 | av_assert1(flags == AVIO_FLAG_WRITE || flags == AVIO_FLAG_READ); |
998 | |
999 | if (flags & AVIO_FLAG_WRITE) { |
1000 | s->buf_end = s->buffer + s->buffer_size; |
1001 | s->write_flag = 1; |
1002 | } else { |
1003 | s->buf_end = s->buffer; |
1004 | s->write_flag = 0; |
1005 | } |
1006 | return 0; |
1007 | } |
1008 | |
1009 | int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **bufp, int buf_size) |
1010 | { |
1011 | int64_t buffer_start; |
1012 | int buffer_size; |
1013 | int overlap, new_size, alloc_size; |
1014 | uint8_t *buf = *bufp; |
1015 | |
1016 | if (s->write_flag) { |
1017 | av_freep(bufp); |
1018 | return AVERROR(EINVAL); |
1019 | } |
1020 | |
1021 | buffer_size = s->buf_end - s->buffer; |
1022 | |
1023 | /* the buffers must touch or overlap */ |
1024 | if ((buffer_start = s->pos - buffer_size) > buf_size) { |
1025 | av_freep(bufp); |
1026 | return AVERROR(EINVAL); |
1027 | } |
1028 | |
1029 | overlap = buf_size - buffer_start; |
1030 | new_size = buf_size + buffer_size - overlap; |
1031 | |
1032 | alloc_size = FFMAX(s->buffer_size, new_size); |
1033 | if (alloc_size > buf_size) |
1034 | if (!(buf = (*bufp) = av_realloc_f(buf, 1, alloc_size))) |
1035 | return AVERROR(ENOMEM); |
1036 | |
1037 | if (new_size > buf_size) { |
1038 | memcpy(buf + buf_size, s->buffer + overlap, buffer_size - overlap); |
1039 | buf_size = new_size; |
1040 | } |
1041 | |
1042 | av_free(s->buffer); |
1043 | s->buf_ptr = s->buffer = buf; |
1044 | s->buffer_size = alloc_size; |
1045 | s->pos = buf_size; |
1046 | s->buf_end = s->buf_ptr + buf_size; |
1047 | s->eof_reached = 0; |
1048 | s->must_flush = 0; |
1049 | |
1050 | return 0; |
1051 | } |
1052 | |
1053 | int avio_open(AVIOContext **s, const char *filename, int flags) |
1054 | { |
1055 | return avio_open2(s, filename, flags, NULL, NULL); |
1056 | } |
1057 | |
1058 | int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags, |
1059 | const AVIOInterruptCB *int_cb, AVDictionary **options, |
1060 | const char *whitelist, const char *blacklist |
1061 | ) |
1062 | { |
1063 | URLContext *h; |
1064 | int err; |
1065 | |
1066 | err = ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist, blacklist, NULL); |
1067 | if (err < 0) |
1068 | return err; |
1069 | err = ffio_fdopen(s, h); |
1070 | if (err < 0) { |
1071 | ffurl_close(h); |
1072 | return err; |
1073 | } |
1074 | return 0; |
1075 | } |
1076 | |
1077 | int avio_open2(AVIOContext **s, const char *filename, int flags, |
1078 | const AVIOInterruptCB *int_cb, AVDictionary **options) |
1079 | { |
1080 | return ffio_open_whitelist(s, filename, flags, int_cb, options, NULL, NULL); |
1081 | } |
1082 | |
1083 | int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, |
1084 | const AVIOInterruptCB *int_cb, AVDictionary **options) |
1085 | { |
1086 | return ffio_open_whitelist(pb, url, flags, int_cb, options, s->protocol_whitelist, s->protocol_blacklist); |
1087 | } |
1088 | |
1089 | int avio_close(AVIOContext *s) |
1090 | { |
1091 | AVIOInternal *internal; |
1092 | URLContext *h; |
1093 | |
1094 | if (!s) |
1095 | return 0; |
1096 | |
1097 | avio_flush(s); |
1098 | internal = s->opaque; |
1099 | h = internal->h; |
1100 | |
1101 | av_freep(&s->opaque); |
1102 | av_freep(&s->buffer); |
1103 | if (s->write_flag) |
1104 | av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count); |
1105 | else |
1106 | av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count); |
1107 | av_opt_free(s); |
1108 | av_free(s); |
1109 | return ffurl_close(h); |
1110 | } |
1111 | |
1112 | int avio_closep(AVIOContext **s) |
1113 | { |
1114 | int ret = avio_close(*s); |
1115 | *s = NULL; |
1116 | return ret; |
1117 | } |
1118 | |
1119 | int avio_printf(AVIOContext *s, const char *fmt, ...) |
1120 | { |
1121 | va_list ap; |
1122 | char buf[4096]; /* update doc entry in avio.h if changed */ |
1123 | int ret; |
1124 | |
1125 | va_start(ap, fmt); |
1126 | ret = vsnprintf(buf, sizeof(buf), fmt, ap); |
1127 | va_end(ap); |
1128 | avio_write(s, buf, strlen(buf)); |
1129 | return ret; |
1130 | } |
1131 | |
1132 | int avio_pause(AVIOContext *s, int pause) |
1133 | { |
1134 | if (!s->read_pause) |
1135 | return AVERROR(ENOSYS); |
1136 | return s->read_pause(s->opaque, pause); |
1137 | } |
1138 | |
1139 | int64_t avio_seek_time(AVIOContext *s, int stream_index, |
1140 | int64_t timestamp, int flags) |
1141 | { |
1142 | int64_t ret; |
1143 | if (!s->read_seek) |
1144 | return AVERROR(ENOSYS); |
1145 | ret = s->read_seek(s->opaque, stream_index, timestamp, flags); |
1146 | if (ret >= 0) { |
1147 | int64_t pos; |
1148 | s->buf_ptr = s->buf_end; // Flush buffer |
1149 | pos = s->seek(s->opaque, 0, SEEK_CUR); |
1150 | if (pos >= 0) |
1151 | s->pos = pos; |
1152 | else if (pos != AVERROR(ENOSYS)) |
1153 | ret = pos; |
1154 | } |
1155 | return ret; |
1156 | } |
1157 | |
1158 | int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size) |
1159 | { |
1160 | int ret; |
1161 | char buf[1024]; |
1162 | while (max_size) { |
1163 | ret = avio_read(h, buf, FFMIN(max_size, sizeof(buf))); |
1164 | if (ret == AVERROR_EOF) |
1165 | return 0; |
1166 | if (ret <= 0) |
1167 | return ret; |
1168 | av_bprint_append_data(pb, buf, ret); |
1169 | if (!av_bprint_is_complete(pb)) |
1170 | return AVERROR(ENOMEM); |
1171 | max_size -= ret; |
1172 | } |
1173 | return 0; |
1174 | } |
1175 | |
1176 | int avio_accept(AVIOContext *s, AVIOContext **c) |
1177 | { |
1178 | int ret; |
1179 | AVIOInternal *internal = s->opaque; |
1180 | URLContext *sc = internal->h; |
1181 | URLContext *cc = NULL; |
1182 | ret = ffurl_accept(sc, &cc); |
1183 | if (ret < 0) |
1184 | return ret; |
1185 | return ffio_fdopen(c, cc); |
1186 | } |
1187 | |
1188 | int avio_handshake(AVIOContext *c) |
1189 | { |
1190 | AVIOInternal *internal = c->opaque; |
1191 | URLContext *cc = internal->h; |
1192 | return ffurl_handshake(cc); |
1193 | } |
1194 | |
1195 | /* output in a dynamic buffer */ |
1196 | |
1197 | typedef struct DynBuffer { |
1198 | int pos, size, allocated_size; |
1199 | uint8_t *buffer; |
1200 | int io_buffer_size; |
1201 | uint8_t io_buffer[1]; |
1202 | } DynBuffer; |
1203 | |
1204 | static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size) |
1205 | { |
1206 | DynBuffer *d = opaque; |
1207 | unsigned new_size, new_allocated_size; |
1208 | |
1209 | /* reallocate buffer if needed */ |
1210 | new_size = d->pos + buf_size; |
1211 | new_allocated_size = d->allocated_size; |
1212 | if (new_size < d->pos || new_size > INT_MAX/2) |
1213 | return -1; |
1214 | while (new_size > new_allocated_size) { |
1215 | if (!new_allocated_size) |
1216 | new_allocated_size = new_size; |
1217 | else |
1218 | new_allocated_size += new_allocated_size / 2 + 1; |
1219 | } |
1220 | |
1221 | if (new_allocated_size > d->allocated_size) { |
1222 | int err; |
1223 | if ((err = av_reallocp(&d->buffer, new_allocated_size)) < 0) { |
1224 | d->allocated_size = 0; |
1225 | d->size = 0; |
1226 | return err; |
1227 | } |
1228 | d->allocated_size = new_allocated_size; |
1229 | } |
1230 | memcpy(d->buffer + d->pos, buf, buf_size); |
1231 | d->pos = new_size; |
1232 | if (d->pos > d->size) |
1233 | d->size = d->pos; |
1234 | return buf_size; |
1235 | } |
1236 | |
1237 | static int dyn_packet_buf_write(void *opaque, uint8_t *buf, int buf_size) |
1238 | { |
1239 | unsigned char buf1[4]; |
1240 | int ret; |
1241 | |
1242 | /* packetized write: output the header */ |
1243 | AV_WB32(buf1, buf_size); |
1244 | ret = dyn_buf_write(opaque, buf1, 4); |
1245 | if (ret < 0) |
1246 | return ret; |
1247 | |
1248 | /* then the data */ |
1249 | return dyn_buf_write(opaque, buf, buf_size); |
1250 | } |
1251 | |
1252 | static int64_t dyn_buf_seek(void *opaque, int64_t offset, int whence) |
1253 | { |
1254 | DynBuffer *d = opaque; |
1255 | |
1256 | if (whence == SEEK_CUR) |
1257 | offset += d->pos; |
1258 | else if (whence == SEEK_END) |
1259 | offset += d->size; |
1260 | if (offset < 0 || offset > 0x7fffffffLL) |
1261 | return -1; |
1262 | d->pos = offset; |
1263 | return 0; |
1264 | } |
1265 | |
1266 | static int url_open_dyn_buf_internal(AVIOContext **s, int max_packet_size) |
1267 | { |
1268 | DynBuffer *d; |
1269 | unsigned io_buffer_size = max_packet_size ? max_packet_size : 1024; |
1270 | |
1271 | if (sizeof(DynBuffer) + io_buffer_size < io_buffer_size) |
1272 | return -1; |
1273 | d = av_mallocz(sizeof(DynBuffer) + io_buffer_size); |
1274 | if (!d) |
1275 | return AVERROR(ENOMEM); |
1276 | d->io_buffer_size = io_buffer_size; |
1277 | *s = avio_alloc_context(d->io_buffer, d->io_buffer_size, 1, d, NULL, |
1278 | max_packet_size ? dyn_packet_buf_write : dyn_buf_write, |
1279 | max_packet_size ? NULL : dyn_buf_seek); |
1280 | if(!*s) { |
1281 | av_free(d); |
1282 | return AVERROR(ENOMEM); |
1283 | } |
1284 | (*s)->max_packet_size = max_packet_size; |
1285 | return 0; |
1286 | } |
1287 | |
1288 | int avio_open_dyn_buf(AVIOContext **s) |
1289 | { |
1290 | return url_open_dyn_buf_internal(s, 0); |
1291 | } |
1292 | |
1293 | int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size) |
1294 | { |
1295 | if (max_packet_size <= 0) |
1296 | return -1; |
1297 | return url_open_dyn_buf_internal(s, max_packet_size); |
1298 | } |
1299 | |
1300 | int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer) |
1301 | { |
1302 | DynBuffer *d; |
1303 | |
1304 | if (!s) { |
1305 | *pbuffer = NULL; |
1306 | return 0; |
1307 | } |
1308 | |
1309 | avio_flush(s); |
1310 | |
1311 | d = s->opaque; |
1312 | *pbuffer = d->buffer; |
1313 | |
1314 | return d->size; |
1315 | } |
1316 | |
1317 | int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) |
1318 | { |
1319 | DynBuffer *d; |
1320 | int size; |
1321 | static const char padbuf[AV_INPUT_BUFFER_PADDING_SIZE] = {0}; |
1322 | int padding = 0; |
1323 | |
1324 | if (!s) { |
1325 | *pbuffer = NULL; |
1326 | return 0; |
1327 | } |
1328 | |
1329 | /* don't attempt to pad fixed-size packet buffers */ |
1330 | if (!s->max_packet_size) { |
1331 | avio_write(s, padbuf, sizeof(padbuf)); |
1332 | padding = AV_INPUT_BUFFER_PADDING_SIZE; |
1333 | } |
1334 | |
1335 | avio_flush(s); |
1336 | |
1337 | d = s->opaque; |
1338 | *pbuffer = d->buffer; |
1339 | size = d->size; |
1340 | av_free(d); |
1341 | av_free(s); |
1342 | return size - padding; |
1343 | } |
1344 | |
1345 | void ffio_free_dyn_buf(AVIOContext **s) |
1346 | { |
1347 | uint8_t *tmp; |
1348 | if (!*s) |
1349 | return; |
1350 | avio_close_dyn_buf(*s, &tmp); |
1351 | av_free(tmp); |
1352 | *s = NULL; |
1353 | } |
1354 | |
1355 | static int null_buf_write(void *opaque, uint8_t *buf, int buf_size) |
1356 | { |
1357 | DynBuffer *d = opaque; |
1358 | |
1359 | d->pos += buf_size; |
1360 | if (d->pos > d->size) |
1361 | d->size = d->pos; |
1362 | return buf_size; |
1363 | } |
1364 | |
1365 | int ffio_open_null_buf(AVIOContext **s) |
1366 | { |
1367 | int ret = url_open_dyn_buf_internal(s, 0); |
1368 | if (ret >= 0) { |
1369 | AVIOContext *pb = *s; |
1370 | pb->write_packet = null_buf_write; |
1371 | } |
1372 | return ret; |
1373 | } |
1374 | |
1375 | int ffio_close_null_buf(AVIOContext *s) |
1376 | { |
1377 | DynBuffer *d = s->opaque; |
1378 | int size; |
1379 | |
1380 | avio_flush(s); |
1381 | |
1382 | size = d->size; |
1383 | av_free(d); |
1384 | av_free(s); |
1385 | return size; |
1386 | } |
1387 |