return NULL;
}
-static const AVOption options[] = { { NULL } };
+static const AVOption options[] = {
+ { "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 },
+ { NULL }
+};
const AVClass ffurl_context_class = {
.class_name = "URLContext",
.item_name = urlcontext_to_name,
static int url_alloc_for_protocol(URLContext **puc, const URLProtocol *up,
const char *filename, int flags,
- const AVIOInterruptCB *int_cb)
+ const AVIOInterruptCB *int_cb,
+ const URLProtocol **protocols)
{
URLContext *uc;
int err;
uc->flags = flags;
uc->is_streamed = 0; /* default = not streamed */
uc->max_packet_size = 0; /* default: stream file */
+ uc->protocols = protocols;
if (up->priv_data_size) {
uc->priv_data = av_mallocz(up->priv_data_size);
if (!uc->priv_data) {
"0123456789+-."
int ffurl_alloc(URLContext **puc, const char *filename, int flags,
- const AVIOInterruptCB *int_cb)
+ const AVIOInterruptCB *int_cb,
+ const URLProtocol **protocols)
{
- const URLProtocol **protocols;
char proto_str[128], proto_nested[128], *ptr;
size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
int i;
if ((ptr = strchr(proto_nested, '+')))
*ptr = '\0';
- protocols = ffurl_get_protocols(NULL, NULL);
for (i = 0; protocols[i]; i++) {
const URLProtocol *up = protocols[i];
- if (!strcmp(proto_str, up->name)) {
- av_freep(&protocols);
- return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
- }
+ if (!strcmp(proto_str, up->name))
+ return url_alloc_for_protocol(puc, up, filename, flags, int_cb,
+ protocols);
if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
- !strcmp(proto_nested, up->name)) {
- av_freep(&protocols);
- return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
- }
+ !strcmp(proto_nested, up->name))
+ return url_alloc_for_protocol(puc, up, filename, flags, int_cb,
+ protocols);
}
*puc = NULL;
return AVERROR_PROTOCOL_NOT_FOUND;
}
int ffurl_open(URLContext **puc, const char *filename, int flags,
- const AVIOInterruptCB *int_cb, AVDictionary **options)
+ const AVIOInterruptCB *int_cb, AVDictionary **options,
+ const URLProtocol **protocols,
+ URLContext *parent)
{
- int ret = ffurl_alloc(puc, filename, flags, int_cb);
+ int ret = ffurl_alloc(puc, filename, flags, int_cb, protocols);
if (ret)
return ret;
+ if (parent)
+ av_opt_copy(*puc, parent);
+ if (options &&
+ (ret = av_opt_set_dict(*puc, options)) < 0)
+ goto fail;
if (options && (*puc)->prot->priv_data_class &&
(ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
goto fail;
{
int ret, len;
int fast_retries = 5;
+ int64_t wait_since = 0;
len = 0;
while (len < size_min) {
return ret;
if (ret == AVERROR(EAGAIN)) {
ret = 0;
- if (fast_retries)
+ if (fast_retries) {
fast_retries--;
- else
+ } else {
+ if (h->rw_timeout) {
+ if (!wait_since)
+ wait_since = av_gettime_relative();
+ else if (av_gettime_relative() > wait_since + h->rw_timeout)
+ return AVERROR(EIO);
+ }
av_usleep(1000);
+ }
} else if (ret < 1)
return (ret < 0 && ret != AVERROR_EOF) ? ret : len;
- if (ret)
+ if (ret) {
fast_retries = FFMAX(fast_retries, 2);
+ wait_since = 0;
+ }
len += ret;
if (ff_check_interrupt(&h->interrupt_callback))
return AVERROR_EXIT;
int avio_check(const char *url, int flags)
{
+ const URLProtocol **protocols;
URLContext *h;
- int ret = ffurl_alloc(&h, url, flags, NULL);
- if (ret)
+ int ret;
+
+ protocols = ffurl_get_protocols(NULL, NULL);
+ if (!protocols)
+ return AVERROR(ENOMEM);
+
+ ret = ffurl_alloc(&h, url, flags, NULL, protocols);
+ if (ret) {
+ av_freep(&protocols);
return ret;
+ }
if (h->prot->url_check) {
ret = h->prot->url_check(h, flags);
}
ffurl_close(h);
+ av_freep(&protocols);
return ret;
}