3 * Copyright (c) 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/avstring.h"
23 #include "libavutil/dict.h"
24 #include "libavutil/mem.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/time.h"
27 #include "libavutil/avassert.h"
28 #include "avio_internal.h"
29 #include "os_support.h"
36 #define IO_BUFFER_SIZE 32768
38 /** @name Logging context. */
40 static const char *urlcontext_to_name(void *ptr
)
42 URLContext
*h
= (URLContext
*)ptr
;
49 static void *urlcontext_child_next(void *obj
, void *prev
)
52 if (!prev
&& h
->priv_data
&& h
->prot
->priv_data_class
)
57 #define OFFSET(x) offsetof(URLContext,x)
58 #define E AV_OPT_FLAG_ENCODING_PARAM
59 #define D AV_OPT_FLAG_DECODING_PARAM
60 static const AVOption options
[] = {
61 {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, 0, 0, D
},
62 {"protocol_blacklist", "List of protocols that are not allowed to be used", OFFSET(protocol_blacklist
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, 0, 0, D
},
63 {"rw_timeout", "Timeout for IO operations (in microseconds)", offsetof(URLContext
, rw_timeout
), AV_OPT_TYPE_INT64
, { .i64
= 0 }, 0, INT64_MAX
, AV_OPT_FLAG_ENCODING_PARAM
| AV_OPT_FLAG_DECODING_PARAM
},
67 static const AVClass url_context_class
= {
68 .class_name
= "URLContext",
69 .item_name
= urlcontext_to_name
,
71 .version
= LIBAVUTIL_VERSION_INT
,
72 .child_next
= urlcontext_child_next
,
73 .child_class_iterate
= ff_urlcontext_child_class_iterate
,
77 static void *avio_child_next(void *obj
, void *prev
)
80 return prev
? NULL
: s
->opaque
;
83 static const AVClass
*child_class_iterate(void **iter
)
85 const AVClass
*c
= *iter
? NULL
: &url_context_class
;
86 *iter
= (void*)(uintptr_t)c
;
90 #define AVIOOFFSET(x) offsetof(AVIOContext,x)
91 #define E AV_OPT_FLAG_ENCODING_PARAM
92 #define D AV_OPT_FLAG_DECODING_PARAM
93 static const AVOption avio_options
[] = {
94 {"protocol_whitelist", "List of protocols that are allowed to be used", AVIOOFFSET(protocol_whitelist
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, 0, 0, D
},
98 const AVClass ff_avio_class
= {
99 .class_name
= "AVIOContext",
100 .item_name
= av_default_item_name
,
101 .version
= LIBAVUTIL_VERSION_INT
,
102 .option
= avio_options
,
103 .child_next
= avio_child_next
,
104 .child_class_iterate
= child_class_iterate
,
107 URLContext
*ffio_geturlcontext(AVIOContext
*s
)
112 if (s
->opaque
&& s
->read_packet
== ffurl_read2
)
118 static int url_alloc_for_protocol(URLContext
**puc
, const URLProtocol
*up
,
119 const char *filename
, int flags
,
120 const AVIOInterruptCB
*int_cb
)
126 if (up
->flags
& URL_PROTOCOL_FLAG_NETWORK
&& !ff_network_init())
129 if ((flags
& AVIO_FLAG_READ
) && !up
->url_read
) {
130 av_log(NULL
, AV_LOG_ERROR
,
131 "Impossible to open the '%s' protocol for reading\n", up
->name
);
134 if ((flags
& AVIO_FLAG_WRITE
) && !up
->url_write
) {
135 av_log(NULL
, AV_LOG_ERROR
,
136 "Impossible to open the '%s' protocol for writing\n", up
->name
);
139 uc
= av_mallocz(sizeof(URLContext
) + strlen(filename
) + 1);
141 err
= AVERROR(ENOMEM
);
144 uc
->av_class
= &url_context_class
;
145 uc
->filename
= (char *)&uc
[1];
146 strcpy(uc
->filename
, filename
);
149 uc
->is_streamed
= 0; /* default = not streamed */
150 uc
->max_packet_size
= 0; /* default: stream file */
151 if (up
->priv_data_size
) {
152 uc
->priv_data
= av_mallocz(up
->priv_data_size
);
153 if (!uc
->priv_data
) {
154 err
= AVERROR(ENOMEM
);
157 if (up
->priv_data_class
) {
159 *(const AVClass
**)uc
->priv_data
= up
->priv_data_class
;
160 av_opt_set_defaults(uc
->priv_data
);
161 if (av_strstart(uc
->filename
, up
->name
, (const char**)&start
) && *start
== ',') {
168 if (strcmp(up
->name
, "subfile"))
169 ret
= AVERROR(EINVAL
);
171 while(ret
>= 0 && (key
= strchr(p
, sep
)) && p
<key
&& (val
= strchr(key
+1, sep
))){
173 ret
= av_opt_set(uc
->priv_data
, p
, key
+1, 0);
174 if (ret
== AVERROR_OPTION_NOT_FOUND
)
175 av_log(uc
, AV_LOG_ERROR
, "Key '%s' not found.\n", p
);
180 av_log(uc
, AV_LOG_ERROR
, "Error parsing options string %s\n", start
);
181 err
= AVERROR(EINVAL
);
184 memmove(start
, key
+1, strlen(key
));
189 uc
->interrupt_callback
= *int_cb
;
196 av_freep(&uc
->priv_data
);
199 if (up
->flags
& URL_PROTOCOL_FLAG_NETWORK
)
205 int ffurl_connect(URLContext
*uc
, AVDictionary
**options
)
208 AVDictionary
*tmp_opts
= NULL
;
209 AVDictionaryEntry
*e
;
214 // Check that URLContext was initialized correctly and lists are matching if set
215 av_assert0(!(e
=av_dict_get(*options
, "protocol_whitelist", NULL
, 0)) ||
216 (uc
->protocol_whitelist
&& !strcmp(uc
->protocol_whitelist
, e
->value
)));
217 av_assert0(!(e
=av_dict_get(*options
, "protocol_blacklist", NULL
, 0)) ||
218 (uc
->protocol_blacklist
&& !strcmp(uc
->protocol_blacklist
, e
->value
)));
220 if (uc
->protocol_whitelist
&& av_match_list(uc
->prot
->name
, uc
->protocol_whitelist
, ',') <= 0) {
221 av_log(uc
, AV_LOG_ERROR
, "Protocol '%s' not on whitelist '%s'!\n", uc
->prot
->name
, uc
->protocol_whitelist
);
222 return AVERROR(EINVAL
);
225 if (uc
->protocol_blacklist
&& av_match_list(uc
->prot
->name
, uc
->protocol_blacklist
, ',') > 0) {
226 av_log(uc
, AV_LOG_ERROR
, "Protocol '%s' on blacklist '%s'!\n", uc
->prot
->name
, uc
->protocol_blacklist
);
227 return AVERROR(EINVAL
);
230 if (!uc
->protocol_whitelist
&& uc
->prot
->default_whitelist
) {
231 av_log(uc
, AV_LOG_DEBUG
, "Setting default whitelist '%s'\n", uc
->prot
->default_whitelist
);
232 uc
->protocol_whitelist
= av_strdup(uc
->prot
->default_whitelist
);
233 if (!uc
->protocol_whitelist
) {
234 return AVERROR(ENOMEM
);
236 } else if (!uc
->protocol_whitelist
)
237 av_log(uc
, AV_LOG_DEBUG
, "No default whitelist set\n"); // This should be an error once all declare a default whitelist
239 if ((err
= av_dict_set(options
, "protocol_whitelist", uc
->protocol_whitelist
, 0)) < 0)
241 if ((err
= av_dict_set(options
, "protocol_blacklist", uc
->protocol_blacklist
, 0)) < 0)
245 uc
->prot
->url_open2
? uc
->prot
->url_open2(uc
,
249 uc
->prot
->url_open(uc
, uc
->filename
, uc
->flags
);
251 av_dict_set(options
, "protocol_whitelist", NULL
, 0);
252 av_dict_set(options
, "protocol_blacklist", NULL
, 0);
256 uc
->is_connected
= 1;
257 /* We must be careful here as ffurl_seek() could be slow,
258 * for example for http */
259 if ((uc
->flags
& AVIO_FLAG_WRITE
) || !strcmp(uc
->prot
->name
, "file"))
260 if (!uc
->is_streamed
&& ffurl_seek(uc
, 0, SEEK_SET
) < 0)
265 int ffurl_accept(URLContext
*s
, URLContext
**c
)
268 if (s
->prot
->url_accept
)
269 return s
->prot
->url_accept(s
, c
);
270 return AVERROR(EBADF
);
273 int avio_accept(AVIOContext
*s
, AVIOContext
**c
)
276 URLContext
*sc
= s
->opaque
;
277 URLContext
*cc
= NULL
;
278 ret
= ffurl_accept(sc
, &cc
);
281 return ffio_fdopen(c
, cc
);
284 int ffurl_handshake(URLContext
*c
)
287 if (c
->prot
->url_handshake
) {
288 ret
= c
->prot
->url_handshake(c
);
296 int avio_handshake(AVIOContext
*c
)
298 URLContext
*cc
= c
->opaque
;
299 return ffurl_handshake(cc
);
302 #define URL_SCHEME_CHARS \
303 "abcdefghijklmnopqrstuvwxyz" \
304 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
307 static const struct URLProtocol
*url_find_protocol(const char *filename
)
309 const URLProtocol
**protocols
;
310 char proto_str
[128], proto_nested
[128], *ptr
;
311 size_t proto_len
= strspn(filename
, URL_SCHEME_CHARS
);
314 if (filename
[proto_len
] != ':' &&
315 (strncmp(filename
, "subfile,", 8) || !strchr(filename
+ proto_len
+ 1, ':')) ||
316 is_dos_path(filename
))
317 strcpy(proto_str
, "file");
319 av_strlcpy(proto_str
, filename
,
320 FFMIN(proto_len
+ 1, sizeof(proto_str
)));
322 av_strlcpy(proto_nested
, proto_str
, sizeof(proto_nested
));
323 if ((ptr
= strchr(proto_nested
, '+')))
326 protocols
= ffurl_get_protocols(NULL
, NULL
);
329 for (i
= 0; protocols
[i
]; i
++) {
330 const URLProtocol
*up
= protocols
[i
];
331 if (!strcmp(proto_str
, up
->name
)) {
332 av_freep(&protocols
);
335 if (up
->flags
& URL_PROTOCOL_FLAG_NESTED_SCHEME
&&
336 !strcmp(proto_nested
, up
->name
)) {
337 av_freep(&protocols
);
341 av_freep(&protocols
);
342 if (av_strstart(filename
, "https:", NULL
) || av_strstart(filename
, "tls:", NULL
) ||
343 av_strstart(filename
, "dtls:", NULL
))
344 av_log(NULL
, AV_LOG_WARNING
, "https or dtls protocol not found, recompile FFmpeg with "
345 "openssl, gnutls or securetransport enabled.\n");
350 int ffurl_alloc(URLContext
**puc
, const char *filename
, int flags
,
351 const AVIOInterruptCB
*int_cb
)
353 const URLProtocol
*p
= NULL
;
355 p
= url_find_protocol(filename
);
357 return url_alloc_for_protocol(puc
, p
, filename
, flags
, int_cb
);
360 return AVERROR_PROTOCOL_NOT_FOUND
;
363 int ffurl_open_whitelist(URLContext
**puc
, const char *filename
, int flags
,
364 const AVIOInterruptCB
*int_cb
, AVDictionary
**options
,
365 const char *whitelist
, const char* blacklist
,
368 AVDictionary
*tmp_opts
= NULL
;
369 AVDictionaryEntry
*e
;
370 int ret
= ffurl_alloc(puc
, filename
, flags
, int_cb
);
374 ret
= av_opt_copy(*puc
, parent
);
379 (ret
= av_opt_set_dict(*puc
, options
)) < 0)
381 if (options
&& (*puc
)->prot
->priv_data_class
&&
382 (ret
= av_opt_set_dict((*puc
)->priv_data
, options
)) < 0)
388 av_assert0(!whitelist
||
389 !(e
=av_dict_get(*options
, "protocol_whitelist", NULL
, 0)) ||
390 !strcmp(whitelist
, e
->value
));
391 av_assert0(!blacklist
||
392 !(e
=av_dict_get(*options
, "protocol_blacklist", NULL
, 0)) ||
393 !strcmp(blacklist
, e
->value
));
395 if ((ret
= av_dict_set(options
, "protocol_whitelist", whitelist
, 0)) < 0)
398 if ((ret
= av_dict_set(options
, "protocol_blacklist", blacklist
, 0)) < 0)
401 if ((ret
= av_opt_set_dict(*puc
, options
)) < 0)
404 ret
= ffurl_connect(*puc
, options
);
413 int ffio_fdopen(AVIOContext
**sp
, URLContext
*h
)
416 uint8_t *buffer
= NULL
;
417 int buffer_size
, max_packet_size
;
419 max_packet_size
= h
->max_packet_size
;
420 if (max_packet_size
) {
421 buffer_size
= max_packet_size
; /* no need to bufferize more than one packet */
423 buffer_size
= IO_BUFFER_SIZE
;
425 if (!(h
->flags
& AVIO_FLAG_WRITE
) && h
->is_streamed
) {
426 if (buffer_size
> INT_MAX
/2)
427 return AVERROR(EINVAL
);
430 buffer
= av_malloc(buffer_size
);
432 return AVERROR(ENOMEM
);
434 *sp
= avio_alloc_context(buffer
, buffer_size
, h
->flags
& AVIO_FLAG_WRITE
, h
,
435 ffurl_read2
, ffurl_write2
, ffurl_seek2
);
438 return AVERROR(ENOMEM
);
441 if (h
->protocol_whitelist
) {
442 s
->protocol_whitelist
= av_strdup(h
->protocol_whitelist
);
443 if (!s
->protocol_whitelist
) {
445 return AVERROR(ENOMEM
);
448 if (h
->protocol_blacklist
) {
449 s
->protocol_blacklist
= av_strdup(h
->protocol_blacklist
);
450 if (!s
->protocol_blacklist
) {
452 return AVERROR(ENOMEM
);
455 s
->direct
= h
->flags
& AVIO_FLAG_DIRECT
;
457 s
->seekable
= h
->is_streamed
? 0 : AVIO_SEEKABLE_NORMAL
;
458 s
->max_packet_size
= max_packet_size
;
459 s
->min_packet_size
= h
->min_packet_size
;
461 s
->read_pause
= h
->prot
->url_read_pause
;
462 s
->read_seek
= h
->prot
->url_read_seek
;
464 if (h
->prot
->url_read_seek
)
465 s
->seekable
|= AVIO_SEEKABLE_TIME
;
467 ((FFIOContext
*)s
)->short_seek_get
= ffurl_get_short_seek
;
468 s
->av_class
= &ff_avio_class
;
472 int ffio_open_whitelist(AVIOContext
**s
, const char *filename
, int flags
,
473 const AVIOInterruptCB
*int_cb
, AVDictionary
**options
,
474 const char *whitelist
, const char *blacklist
)
481 err
= ffurl_open_whitelist(&h
, filename
, flags
, int_cb
, options
, whitelist
, blacklist
, NULL
);
484 err
= ffio_fdopen(s
, h
);
492 int avio_open2(AVIOContext
**s
, const char *filename
, int flags
,
493 const AVIOInterruptCB
*int_cb
, AVDictionary
**options
)
495 return ffio_open_whitelist(s
, filename
, flags
, int_cb
, options
, NULL
, NULL
);
498 int avio_open(AVIOContext
**s
, const char *filename
, int flags
)
500 return avio_open2(s
, filename
, flags
, NULL
, NULL
);
504 static inline int retry_transfer_wrapper(URLContext
*h
, uint8_t *buf
,
506 int size
, int size_min
,
510 int fast_retries
= 5;
511 int64_t wait_since
= 0;
514 while (len
< size_min
) {
515 if (ff_check_interrupt(&h
->interrupt_callback
))
517 ret
= read
? h
->prot
->url_read (h
, buf
+ len
, size
- len
):
518 h
->prot
->url_write(h
, cbuf
+ len
, size
- len
);
519 if (ret
== AVERROR(EINTR
))
521 if (h
->flags
& AVIO_FLAG_NONBLOCK
)
523 if (ret
== AVERROR(EAGAIN
)) {
530 wait_since
= av_gettime_relative();
531 else if (av_gettime_relative() > wait_since
+ h
->rw_timeout
)
536 } else if (ret
== AVERROR_EOF
)
537 return (len
> 0) ? len
: AVERROR_EOF
;
541 fast_retries
= FFMAX(fast_retries
, 2);
549 int ffurl_read2(void *urlcontext
, uint8_t *buf
, int size
)
551 URLContext
*h
= urlcontext
;
553 if (!(h
->flags
& AVIO_FLAG_READ
))
555 return retry_transfer_wrapper(h
, buf
, NULL
, size
, 1, 1);
558 int ffurl_read_complete(URLContext
*h
, unsigned char *buf
, int size
)
560 if (!(h
->flags
& AVIO_FLAG_READ
))
562 return retry_transfer_wrapper(h
, buf
, NULL
, size
, size
, 1);
565 int ffurl_write2(void *urlcontext
, const uint8_t *buf
, int size
)
567 URLContext
*h
= urlcontext
;
569 if (!(h
->flags
& AVIO_FLAG_WRITE
))
571 /* avoid sending too big packets */
572 if (h
->max_packet_size
&& size
> h
->max_packet_size
)
575 return retry_transfer_wrapper(h
, NULL
, buf
, size
, size
, 0);
578 int64_t ffurl_seek2(void *urlcontext
, int64_t pos
, int whence
)
580 URLContext
*h
= urlcontext
;
583 if (!h
->prot
->url_seek
)
584 return AVERROR(ENOSYS
);
585 ret
= h
->prot
->url_seek(h
, pos
, whence
& ~AVSEEK_FORCE
);
589 int ffurl_closep(URLContext
**hh
)
594 return 0; /* can happen when ffurl_open fails */
596 if (h
->is_connected
&& h
->prot
->url_close
)
597 ret
= h
->prot
->url_close(h
);
599 if (h
->prot
->flags
& URL_PROTOCOL_FLAG_NETWORK
)
602 if (h
->prot
->priv_data_size
) {
603 if (h
->prot
->priv_data_class
)
604 av_opt_free(h
->priv_data
);
605 av_freep(&h
->priv_data
);
612 int ffurl_close(URLContext
*h
)
614 return ffurl_closep(&h
);
617 int avio_close(AVIOContext
*s
)
619 FFIOContext
*const ctx
= ffiocontext(s
);
630 av_freep(&s
->buffer
);
632 av_log(s
, AV_LOG_VERBOSE
,
633 "Statistics: %"PRId64
" bytes written, %d seeks, %d writeouts\n",
634 ctx
->bytes_written
, ctx
->seek_count
, ctx
->writeout_count
);
636 av_log(s
, AV_LOG_VERBOSE
, "Statistics: %"PRId64
" bytes read, %d seeks\n",
637 ctx
->bytes_read
, ctx
->seek_count
);
641 avio_context_free(&s
);
643 ret
= ffurl_close(h
);
650 int avio_closep(AVIOContext
**s
)
652 int ret
= avio_close(*s
);
658 const char *avio_find_protocol_name(const char *url
)
660 const URLProtocol
*p
= url_find_protocol(url
);
662 return p
? p
->name
: NULL
;
665 int avio_check(const char *url
, int flags
)
668 int ret
= ffurl_alloc(&h
, url
, flags
, NULL
);
672 if (h
->prot
->url_check
) {
673 ret
= h
->prot
->url_check(h
, flags
);
675 ret
= ffurl_connect(h
, NULL
);
684 int ffurl_move(const char *url_src
, const char *url_dst
)
686 URLContext
*h_src
, *h_dst
;
687 int ret
= ffurl_alloc(&h_src
, url_src
, AVIO_FLAG_READ_WRITE
, NULL
);
690 ret
= ffurl_alloc(&h_dst
, url_dst
, AVIO_FLAG_WRITE
, NULL
);
696 if (h_src
->prot
== h_dst
->prot
&& h_src
->prot
->url_move
)
697 ret
= h_src
->prot
->url_move(h_src
, h_dst
);
699 ret
= AVERROR(ENOSYS
);
706 int ffurl_delete(const char *url
)
709 int ret
= ffurl_alloc(&h
, url
, AVIO_FLAG_WRITE
, NULL
);
713 if (h
->prot
->url_delete
)
714 ret
= h
->prot
->url_delete(h
);
716 ret
= AVERROR(ENOSYS
);
722 struct AVIODirContext
{
723 struct URLContext
*url_context
;
726 int avio_open_dir(AVIODirContext
**s
, const char *url
, AVDictionary
**options
)
728 URLContext
*h
= NULL
;
729 AVIODirContext
*ctx
= NULL
;
733 ctx
= av_mallocz(sizeof(*ctx
));
735 ret
= AVERROR(ENOMEM
);
739 if ((ret
= ffurl_alloc(&h
, url
, AVIO_FLAG_READ
, NULL
)) < 0)
742 if (h
->prot
->url_open_dir
&& h
->prot
->url_read_dir
&& h
->prot
->url_close_dir
) {
743 if (options
&& h
->prot
->priv_data_class
&&
744 (ret
= av_opt_set_dict(h
->priv_data
, options
)) < 0)
746 ret
= h
->prot
->url_open_dir(h
);
748 ret
= AVERROR(ENOSYS
);
753 ctx
->url_context
= h
;
764 int avio_read_dir(AVIODirContext
*s
, AVIODirEntry
**next
)
769 if (!s
|| !s
->url_context
)
770 return AVERROR(EINVAL
);
772 if ((ret
= h
->prot
->url_read_dir(h
, next
)) < 0)
773 avio_free_directory_entry(next
);
777 int avio_close_dir(AVIODirContext
**s
)
782 if (!(*s
) || !(*s
)->url_context
)
783 return AVERROR(EINVAL
);
784 h
= (*s
)->url_context
;
785 h
->prot
->url_close_dir(h
);
792 void avio_free_directory_entry(AVIODirEntry
**entry
)
794 if (!entry
|| !*entry
)
796 av_free((*entry
)->name
);
800 int64_t ffurl_size(URLContext
*h
)
804 size
= ffurl_seek(h
, 0, AVSEEK_SIZE
);
806 pos
= ffurl_seek(h
, 0, SEEK_CUR
);
807 if ((size
= ffurl_seek(h
, -1, SEEK_END
)) < 0)
810 ffurl_seek(h
, pos
, SEEK_SET
);
815 int ffurl_get_file_handle(URLContext
*h
)
817 if (!h
|| !h
->prot
|| !h
->prot
->url_get_file_handle
)
819 return h
->prot
->url_get_file_handle(h
);
822 int ffurl_get_multi_file_handle(URLContext
*h
, int **handles
, int *numhandles
)
825 return AVERROR(ENOSYS
);
826 if (!h
->prot
->url_get_multi_file_handle
) {
827 if (!h
->prot
->url_get_file_handle
)
828 return AVERROR(ENOSYS
);
829 *handles
= av_malloc(sizeof(**handles
));
831 return AVERROR(ENOMEM
);
833 *handles
[0] = h
->prot
->url_get_file_handle(h
);
836 return h
->prot
->url_get_multi_file_handle(h
, handles
, numhandles
);
839 int ffurl_get_short_seek(void *urlcontext
)
841 URLContext
*h
= urlcontext
;
843 if (!h
|| !h
->prot
|| !h
->prot
->url_get_short_seek
)
844 return AVERROR(ENOSYS
);
845 return h
->prot
->url_get_short_seek(h
);
848 int ffurl_shutdown(URLContext
*h
, int flags
)
850 if (!h
|| !h
->prot
|| !h
->prot
->url_shutdown
)
851 return AVERROR(ENOSYS
);
852 return h
->prot
->url_shutdown(h
, flags
);
855 int ff_check_interrupt(AVIOInterruptCB
*cb
)
857 if (cb
&& cb
->callback
)
858 return cb
->callback(cb
->opaque
);
862 int ff_rename(const char *url_src
, const char *url_dst
, void *logctx
)
864 int ret
= ffurl_move(url_src
, url_dst
);
866 av_log(logctx
, AV_LOG_ERROR
, "failed to rename file %s to %s: %s\n", url_src
, url_dst
, av_err2str(ret
));