X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Favio.c;h=efe1c26683f97719c37d88875026fc1f7a7520b9;hb=e4de71677f3adeac0f74b89ac8df5d417364df2c;hp=8e1854976e267734568ffa18ac2cd4e74dbc2668;hpb=d10361b65856982fe17032590f490d494f1a01e4;p=ffmpeg diff --git a/libavformat/avio.c b/libavformat/avio.c index 8e1854976e2..efe1c26683f 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -2,26 +2,27 @@ * unbuffered I/O * Copyright (c) 2001 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "libavutil/avstring.h" +#include "libavutil/dict.h" #include "libavutil/opt.h" #include "os_support.h" #include "avformat.h" @@ -30,6 +31,13 @@ #endif #include "url.h" +static URLProtocol *first_protocol = NULL; + +URLProtocol *ffurl_protocol_next(URLProtocol *prev) +{ + return prev ? prev->next : first_protocol; +} + /** @name Logging context. */ /*@{*/ static const char *urlcontext_to_name(void *ptr) @@ -38,32 +46,58 @@ static const char *urlcontext_to_name(void *ptr) if(h->prot) return h->prot->name; else return "NULL"; } + +static void *urlcontext_child_next(void *obj, void *prev) +{ + URLContext *h = obj; + if (!prev && h->priv_data && h->prot->priv_data_class) + return h->priv_data; + return NULL; +} + +static const AVClass *urlcontext_child_class_next(const AVClass *prev) +{ + URLProtocol *p = NULL; + + /* find the protocol that corresponds to prev */ + while (prev && (p = ffurl_protocol_next(p))) + if (p->priv_data_class == prev) + break; + + /* find next protocol with priv options */ + while (p = ffurl_protocol_next(p)) + if (p->priv_data_class) + return p->priv_data_class; + return NULL; + +} + static const AVOption options[] = {{NULL}}; -static const AVClass urlcontext_class = { +const AVClass ffurl_context_class = { .class_name = "URLContext", .item_name = urlcontext_to_name, .option = options, .version = LIBAVUTIL_VERSION_INT, + .child_next = urlcontext_child_next, + .child_class_next = urlcontext_child_class_next, }; /*@}*/ -static int default_interrupt_cb(void); -URLProtocol *first_protocol = NULL; +#if FF_API_OLD_INTERRUPT_CB +static int default_interrupt_cb(void); int (*url_interrupt_cb)(void) = default_interrupt_cb; +#endif -#if FF_API_OLD_AVIO URLProtocol *av_protocol_next(URLProtocol *p) { - if(p) return p->next; - else return first_protocol; + return ffurl_protocol_next(p); } -#endif const char *avio_enum_protocols(void **opaque, int output) { URLProtocol **p = opaque; - *p = *p ? (*p)->next : first_protocol; + *p = ffurl_protocol_next(*p); if (!*p) return NULL; if ((output && (*p)->url_write) || (!output && (*p)->url_read)) return (*p)->name; @@ -86,7 +120,8 @@ int ffurl_register_protocol(URLProtocol *protocol, int size) } static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, - const char *filename, int flags) + const char *filename, int flags, + const AVIOInterruptCB *int_cb) { URLContext *uc; int err; @@ -100,7 +135,7 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, err = AVERROR(ENOMEM); goto fail; } - uc->av_class = &urlcontext_class; + uc->av_class = &ffurl_context_class; uc->filename = (char *) &uc[1]; strcpy(uc->filename, filename); uc->prot = up; @@ -110,10 +145,35 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, if (up->priv_data_size) { uc->priv_data = av_mallocz(up->priv_data_size); if (up->priv_data_class) { + char *start = strchr(uc->filename, ','); *(const AVClass**)uc->priv_data = up->priv_data_class; av_opt_set_defaults(uc->priv_data); + if(start){ + int ret= 0; + char *p= start; + char sep= *++p; + char *key, *val; + p++; + while(ret >= 0 && (key= strchr(p, sep)) && ppriv_data, p, key+1, 0); + if (ret == AVERROR_OPTION_NOT_FOUND) + av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p); + *val= *key= sep; + p= val+1; + } + if(ret<0 || p!=key){ + av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start); + av_freep(&uc->priv_data); + av_freep(&uc); + goto fail; + } + memmove(start, key+1, strlen(key)); + } } } + if (int_cb) + uc->interrupt_callback = *int_cb; *puc = uc; return 0; @@ -125,9 +185,13 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, return err; } -int ffurl_connect(URLContext* uc) +int ffurl_connect(URLContext* uc, AVDictionary **options) { - int err = uc->prot->url_open(uc, uc->filename, uc->flags); + int err = +#if !FF_API_OLD_AVIO + uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) : +#endif + uc->prot->url_open(uc, uc->filename, uc->flags); if (err) return err; uc->is_connected = 1; @@ -145,10 +209,10 @@ int url_open_protocol (URLContext **puc, struct URLProtocol *up, { int ret; - ret = url_alloc_for_protocol(puc, up, filename, flags); + ret = url_alloc_for_protocol(puc, up, filename, flags, NULL); if (ret) goto fail; - ret = ffurl_connect(*puc); + ret = ffurl_connect(*puc, NULL); if (!ret) return 0; fail: @@ -158,15 +222,15 @@ int url_open_protocol (URLContext **puc, struct URLProtocol *up, } int url_alloc(URLContext **puc, const char *filename, int flags) { - return ffurl_alloc(puc, filename, flags); + return ffurl_alloc(puc, filename, flags, NULL); } int url_connect(URLContext* uc) { - return ffurl_connect(uc); + return ffurl_connect(uc, NULL); } int url_open(URLContext **puc, const char *filename, int flags) { - return ffurl_open(puc, filename, flags); + return ffurl_open(puc, filename, flags, NULL, NULL); } int url_read(URLContext *h, unsigned char *buf, int size) { @@ -219,42 +283,53 @@ int av_register_protocol2(URLProtocol *protocol, int size) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "0123456789+-." -int ffurl_alloc(URLContext **puc, const char *filename, int flags) +int ffurl_alloc(URLContext **puc, const char *filename, int flags, + const AVIOInterruptCB *int_cb) { - URLProtocol *up; + URLProtocol *up = NULL; char proto_str[128], proto_nested[128], *ptr; size_t proto_len = strspn(filename, URL_SCHEME_CHARS); - if (filename[proto_len] != ':' || is_dos_path(filename)) + if (!first_protocol) { + av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. " + "Missing call to av_register_all()?\n"); + } + + if (filename[proto_len] != ':' && filename[proto_len] != ',' || is_dos_path(filename)) strcpy(proto_str, "file"); else av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str))); + if ((ptr = strchr(proto_str, ','))) + *ptr = '\0'; av_strlcpy(proto_nested, proto_str, sizeof(proto_nested)); if ((ptr = strchr(proto_nested, '+'))) *ptr = '\0'; - up = first_protocol; - while (up != NULL) { + while (up = ffurl_protocol_next(up)) { if (!strcmp(proto_str, up->name)) - return url_alloc_for_protocol (puc, up, filename, flags); + return url_alloc_for_protocol (puc, up, filename, flags, int_cb); if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME && !strcmp(proto_nested, up->name)) - return url_alloc_for_protocol (puc, up, filename, flags); - up = up->next; + return url_alloc_for_protocol (puc, up, filename, flags, int_cb); } *puc = NULL; return AVERROR(ENOENT); } -int ffurl_open(URLContext **puc, const char *filename, int flags) +int ffurl_open(URLContext **puc, const char *filename, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options) { - int ret = ffurl_alloc(puc, filename, flags); + int ret = ffurl_alloc(puc, filename, flags, int_cb); if (ret) return ret; - ret = ffurl_connect(*puc); + if (options && (*puc)->prot->priv_data_class && + (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0) + goto fail; + ret = ffurl_connect(*puc, options); if (!ret) return 0; +fail: ffurl_close(*puc); *puc = NULL; return ret; @@ -284,7 +359,7 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int if (ret) fast_retries = FFMAX(fast_retries, 2); len += ret; - if (url_interrupt_cb()) + if (len < size && ff_check_interrupt(&h->interrupt_callback)) return AVERROR_EXIT; } return len; @@ -312,7 +387,7 @@ int ffurl_write(URLContext *h, const unsigned char *buf, int size) if (h->max_packet_size && size > h->max_packet_size) return AVERROR(EIO); - return retry_transfer_wrapper(h, buf, size, size, h->prot->url_write); + return retry_transfer_wrapper(h, buf, size, size, (void*)h->prot->url_write); } int64_t ffurl_seek(URLContext *h, int64_t pos, int whence) @@ -348,7 +423,7 @@ int ffurl_close(URLContext *h) int url_exist(const char *filename) { URLContext *h; - if (ffurl_open(&h, filename, AVIO_FLAG_READ) < 0) + if (ffurl_open(&h, filename, AVIO_FLAG_READ, NULL, NULL) < 0) return 0; ffurl_close(h); return 1; @@ -358,14 +433,14 @@ int url_exist(const char *filename) int avio_check(const char *url, int flags) { URLContext *h; - int ret = ffurl_alloc(&h, url, flags); + int ret = ffurl_alloc(&h, url, flags, NULL); if (ret) return ret; if (h->prot->url_check) { ret = h->prot->url_check(h, flags); } else { - ret = ffurl_connect(h); + ret = ffurl_connect(h, NULL); if (ret >= 0) ret = flags; } @@ -396,6 +471,7 @@ int ffurl_get_file_handle(URLContext *h) return h->prot->url_get_file_handle(h); } +#if FF_API_OLD_INTERRUPT_CB static int default_interrupt_cb(void) { return 0; @@ -407,6 +483,19 @@ void avio_set_interrupt_cb(int (*interrupt_cb)(void)) interrupt_cb = default_interrupt_cb; url_interrupt_cb = interrupt_cb; } +#endif + +int ff_check_interrupt(AVIOInterruptCB *cb) +{ + int ret; + if (cb && cb->callback && (ret = cb->callback(cb->opaque))) + return ret; +#if FF_API_OLD_INTERRUPT_CB + return url_interrupt_cb(); +#else + return 0; +#endif +} #if FF_API_OLD_AVIO int av_url_read_pause(URLContext *h, int pause)