libavformat/avio.c
Go to the documentation of this file.
00001 /*
00002  * unbuffered I/O
00003  * Copyright (c) 2001 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include <unistd.h>
00023 
00024 #include "libavutil/avstring.h"
00025 #include "libavutil/dict.h"
00026 #include "libavutil/opt.h"
00027 #include "os_support.h"
00028 #include "avformat.h"
00029 #if CONFIG_NETWORK
00030 #include "network.h"
00031 #endif
00032 #include "url.h"
00033 
00034 static URLProtocol *first_protocol = NULL;
00035 
00036 URLProtocol *ffurl_protocol_next(URLProtocol *prev)
00037 {
00038     return prev ? prev->next : first_protocol;
00039 }
00040 
00043 static const char *urlcontext_to_name(void *ptr)
00044 {
00045     URLContext *h = (URLContext *)ptr;
00046     if(h->prot) return h->prot->name;
00047     else        return "NULL";
00048 }
00049 
00050 static void *urlcontext_child_next(void *obj, void *prev)
00051 {
00052     URLContext *h = obj;
00053     if (!prev && h->priv_data && h->prot->priv_data_class)
00054         return h->priv_data;
00055     return NULL;
00056 }
00057 
00058 static const AVClass *urlcontext_child_class_next(const AVClass *prev)
00059 {
00060     URLProtocol *p = NULL;
00061 
00062     /* find the protocol that corresponds to prev */
00063     while (prev && (p = ffurl_protocol_next(p)))
00064         if (p->priv_data_class == prev)
00065             break;
00066 
00067     /* find next protocol with priv options */
00068     while (p = ffurl_protocol_next(p))
00069         if (p->priv_data_class)
00070             return p->priv_data_class;
00071     return NULL;
00072 
00073 }
00074 
00075 static const AVOption options[] = {{NULL}};
00076 const AVClass ffurl_context_class = {
00077     .class_name     = "URLContext",
00078     .item_name      = urlcontext_to_name,
00079     .option         = options,
00080     .version        = LIBAVUTIL_VERSION_INT,
00081     .child_next     = urlcontext_child_next,
00082     .child_class_next = urlcontext_child_class_next,
00083 };
00087 #if FF_API_OLD_INTERRUPT_CB
00088 static int default_interrupt_cb(void);
00089 int (*url_interrupt_cb)(void) = default_interrupt_cb;
00090 #endif
00091 
00092 URLProtocol *av_protocol_next(URLProtocol *p)
00093 {
00094     return ffurl_protocol_next(p);
00095 }
00096 
00097 const char *avio_enum_protocols(void **opaque, int output)
00098 {
00099     URLProtocol **p = opaque;
00100     *p = ffurl_protocol_next(*p);
00101     if (!*p) return NULL;
00102     if ((output && (*p)->url_write) || (!output && (*p)->url_read))
00103         return (*p)->name;
00104     return avio_enum_protocols(opaque, output);
00105 }
00106 
00107 int ffurl_register_protocol(URLProtocol *protocol, int size)
00108 {
00109     URLProtocol **p;
00110     if (size < sizeof(URLProtocol)) {
00111         URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
00112         memcpy(temp, protocol, size);
00113         protocol = temp;
00114     }
00115     p = &first_protocol;
00116     while (*p != NULL) p = &(*p)->next;
00117     *p = protocol;
00118     protocol->next = NULL;
00119     return 0;
00120 }
00121 
00122 static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
00123                                    const char *filename, int flags,
00124                                    const AVIOInterruptCB *int_cb)
00125 {
00126     URLContext *uc;
00127     int err;
00128 
00129 #if CONFIG_NETWORK
00130     if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init())
00131         return AVERROR(EIO);
00132 #endif
00133     uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
00134     if (!uc) {
00135         err = AVERROR(ENOMEM);
00136         goto fail;
00137     }
00138     uc->av_class = &ffurl_context_class;
00139     uc->filename = (char *) &uc[1];
00140     strcpy(uc->filename, filename);
00141     uc->prot = up;
00142     uc->flags = flags;
00143     uc->is_streamed = 0; /* default = not streamed */
00144     uc->max_packet_size = 0; /* default: stream file */
00145     if (up->priv_data_size) {
00146         uc->priv_data = av_mallocz(up->priv_data_size);
00147         if (up->priv_data_class) {
00148             int proto_len= strlen(up->name);
00149             char *start = strchr(uc->filename, ',');
00150             *(const AVClass**)uc->priv_data = up->priv_data_class;
00151             av_opt_set_defaults(uc->priv_data);
00152             if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){
00153                 int ret= 0;
00154                 char *p= start;
00155                 char sep= *++p;
00156                 char *key, *val;
00157                 p++;
00158                 while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){
00159                     *val= *key= 0;
00160                     ret= av_opt_set(uc->priv_data, p, key+1, 0);
00161                     if (ret == AVERROR_OPTION_NOT_FOUND)
00162                         av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p);
00163                     *val= *key= sep;
00164                     p= val+1;
00165                 }
00166                 if(ret<0 || p!=key){
00167                     av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start);
00168                     av_freep(&uc->priv_data);
00169                     av_freep(&uc);
00170                     goto fail;
00171                 }
00172                 memmove(start, key+1, strlen(key));
00173             }
00174         }
00175     }
00176     if (int_cb)
00177         uc->interrupt_callback = *int_cb;
00178 
00179     *puc = uc;
00180     return 0;
00181  fail:
00182     *puc = NULL;
00183 #if CONFIG_NETWORK
00184     if (up->flags & URL_PROTOCOL_FLAG_NETWORK)
00185         ff_network_close();
00186 #endif
00187     return err;
00188 }
00189 
00190 int ffurl_connect(URLContext* uc, AVDictionary **options)
00191 {
00192     int err =
00193 #if !FF_API_OLD_AVIO
00194         uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
00195 #endif
00196         uc->prot->url_open(uc, uc->filename, uc->flags);
00197     if (err)
00198         return err;
00199     uc->is_connected = 1;
00200     //We must be careful here as ffurl_seek() could be slow, for example for http
00201     if(   (uc->flags & AVIO_FLAG_WRITE)
00202        || !strcmp(uc->prot->name, "file"))
00203         if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
00204             uc->is_streamed= 1;
00205     return 0;
00206 }
00207 
00208 #if FF_API_OLD_AVIO
00209 int url_open_protocol (URLContext **puc, struct URLProtocol *up,
00210                        const char *filename, int flags)
00211 {
00212     int ret;
00213 
00214     ret = url_alloc_for_protocol(puc, up, filename, flags, NULL);
00215     if (ret)
00216         goto fail;
00217     ret = ffurl_connect(*puc, NULL);
00218     if (!ret)
00219         return 0;
00220  fail:
00221     ffurl_close(*puc);
00222     *puc = NULL;
00223     return ret;
00224 }
00225 int url_alloc(URLContext **puc, const char *filename, int flags)
00226 {
00227     return ffurl_alloc(puc, filename, flags, NULL);
00228 }
00229 int url_connect(URLContext* uc)
00230 {
00231     return ffurl_connect(uc, NULL);
00232 }
00233 int url_open(URLContext **puc, const char *filename, int flags)
00234 {
00235     return ffurl_open(puc, filename, flags, NULL, NULL);
00236 }
00237 int url_read(URLContext *h, unsigned char *buf, int size)
00238 {
00239     return ffurl_read(h, buf, size);
00240 }
00241 int url_read_complete(URLContext *h, unsigned char *buf, int size)
00242 {
00243     return ffurl_read_complete(h, buf, size);
00244 }
00245 int url_write(URLContext *h, const unsigned char *buf, int size)
00246 {
00247     return ffurl_write(h, buf, size);
00248 }
00249 int64_t url_seek(URLContext *h, int64_t pos, int whence)
00250 {
00251     return ffurl_seek(h, pos, whence);
00252 }
00253 int url_close(URLContext *h)
00254 {
00255     return ffurl_close(h);
00256 }
00257 int64_t url_filesize(URLContext *h)
00258 {
00259     return ffurl_size(h);
00260 }
00261 int url_get_file_handle(URLContext *h)
00262 {
00263     return ffurl_get_file_handle(h);
00264 }
00265 int url_get_max_packet_size(URLContext *h)
00266 {
00267     return h->max_packet_size;
00268 }
00269 void url_get_filename(URLContext *h, char *buf, int buf_size)
00270 {
00271     av_strlcpy(buf, h->filename, buf_size);
00272 }
00273 void url_set_interrupt_cb(URLInterruptCB *interrupt_cb)
00274 {
00275     avio_set_interrupt_cb(interrupt_cb);
00276 }
00277 int av_register_protocol2(URLProtocol *protocol, int size)
00278 {
00279     return ffurl_register_protocol(protocol, size);
00280 }
00281 #endif
00282 
00283 #define URL_SCHEME_CHARS                        \
00284     "abcdefghijklmnopqrstuvwxyz"                \
00285     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                \
00286     "0123456789+-."
00287 
00288 int ffurl_alloc(URLContext **puc, const char *filename, int flags,
00289                 const AVIOInterruptCB *int_cb)
00290 {
00291     URLProtocol *up = NULL;
00292     char proto_str[128], proto_nested[128], *ptr;
00293     size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
00294 
00295     if (!first_protocol) {
00296         av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. "
00297                                      "Missing call to av_register_all()?\n");
00298     }
00299 
00300     if (filename[proto_len] != ':' &&  filename[proto_len] != ',' || is_dos_path(filename))
00301         strcpy(proto_str, "file");
00302     else
00303         av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str)));
00304 
00305     if ((ptr = strchr(proto_str, ',')))
00306         *ptr = '\0';
00307     av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
00308     if ((ptr = strchr(proto_nested, '+')))
00309         *ptr = '\0';
00310 
00311     while (up = ffurl_protocol_next(up)) {
00312         if (!strcmp(proto_str, up->name))
00313             return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
00314         if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
00315             !strcmp(proto_nested, up->name))
00316             return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
00317     }
00318     *puc = NULL;
00319     return AVERROR(ENOENT);
00320 }
00321 
00322 int ffurl_open(URLContext **puc, const char *filename, int flags,
00323                const AVIOInterruptCB *int_cb, AVDictionary **options)
00324 {
00325     int ret = ffurl_alloc(puc, filename, flags, int_cb);
00326     if (ret)
00327         return ret;
00328     if (options && (*puc)->prot->priv_data_class &&
00329         (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
00330         goto fail;
00331     ret = ffurl_connect(*puc, options);
00332     if (!ret)
00333         return 0;
00334 fail:
00335     ffurl_close(*puc);
00336     *puc = NULL;
00337     return ret;
00338 }
00339 
00340 static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min,
00341                                          int (*transfer_func)(URLContext *h, unsigned char *buf, int size))
00342 {
00343     int ret, len;
00344     int fast_retries = 5;
00345 
00346     len = 0;
00347     while (len < size_min) {
00348         ret = transfer_func(h, buf+len, size-len);
00349         if (ret == AVERROR(EINTR))
00350             continue;
00351         if (h->flags & AVIO_FLAG_NONBLOCK)
00352             return ret;
00353         if (ret == AVERROR(EAGAIN)) {
00354             ret = 0;
00355             if (fast_retries)
00356                 fast_retries--;
00357             else
00358                 usleep(1000);
00359         } else if (ret < 1)
00360             return ret < 0 ? ret : len;
00361         if (ret)
00362            fast_retries = FFMAX(fast_retries, 2);
00363         len += ret;
00364         if (len < size && ff_check_interrupt(&h->interrupt_callback))
00365             return AVERROR_EXIT;
00366     }
00367     return len;
00368 }
00369 
00370 int ffurl_read(URLContext *h, unsigned char *buf, int size)
00371 {
00372     if (!(h->flags & AVIO_FLAG_READ))
00373         return AVERROR(EIO);
00374     return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);
00375 }
00376 
00377 int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
00378 {
00379     if (!(h->flags & AVIO_FLAG_READ))
00380         return AVERROR(EIO);
00381     return retry_transfer_wrapper(h, buf, size, size, h->prot->url_read);
00382 }
00383 
00384 int ffurl_write(URLContext *h, const unsigned char *buf, int size)
00385 {
00386     if (!(h->flags & AVIO_FLAG_WRITE))
00387         return AVERROR(EIO);
00388     /* avoid sending too big packets */
00389     if (h->max_packet_size && size > h->max_packet_size)
00390         return AVERROR(EIO);
00391 
00392     return retry_transfer_wrapper(h, buf, size, size, (void*)h->prot->url_write);
00393 }
00394 
00395 int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
00396 {
00397     int64_t ret;
00398 
00399     if (!h->prot->url_seek)
00400         return AVERROR(ENOSYS);
00401     ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
00402     return ret;
00403 }
00404 
00405 int ffurl_close(URLContext *h)
00406 {
00407     int ret = 0;
00408     if (!h) return 0; /* can happen when ffurl_open fails */
00409 
00410     if (h->is_connected && h->prot->url_close)
00411         ret = h->prot->url_close(h);
00412 #if CONFIG_NETWORK
00413     if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)
00414         ff_network_close();
00415 #endif
00416     if (h->prot->priv_data_size) {
00417         if (h->prot->priv_data_class)
00418             av_opt_free(h->priv_data);
00419         av_free(h->priv_data);
00420     }
00421     av_free(h);
00422     return ret;
00423 }
00424 
00425 #if FF_API_OLD_AVIO
00426 int url_exist(const char *filename)
00427 {
00428     URLContext *h;
00429     if (ffurl_open(&h, filename, AVIO_FLAG_READ, NULL, NULL) < 0)
00430         return 0;
00431     ffurl_close(h);
00432     return 1;
00433 }
00434 #endif
00435 
00436 int avio_check(const char *url, int flags)
00437 {
00438     URLContext *h;
00439     int ret = ffurl_alloc(&h, url, flags, NULL);
00440     if (ret)
00441         return ret;
00442 
00443     if (h->prot->url_check) {
00444         ret = h->prot->url_check(h, flags);
00445     } else {
00446         ret = ffurl_connect(h, NULL);
00447         if (ret >= 0)
00448             ret = flags;
00449     }
00450 
00451     ffurl_close(h);
00452     return ret;
00453 }
00454 
00455 int64_t ffurl_size(URLContext *h)
00456 {
00457     int64_t pos, size;
00458 
00459     size= ffurl_seek(h, 0, AVSEEK_SIZE);
00460     if(size<0){
00461         pos = ffurl_seek(h, 0, SEEK_CUR);
00462         if ((size = ffurl_seek(h, -1, SEEK_END)) < 0)
00463             return size;
00464         size++;
00465         ffurl_seek(h, pos, SEEK_SET);
00466     }
00467     return size;
00468 }
00469 
00470 int ffurl_get_file_handle(URLContext *h)
00471 {
00472     if (!h->prot->url_get_file_handle)
00473         return -1;
00474     return h->prot->url_get_file_handle(h);
00475 }
00476 
00477 #if FF_API_OLD_INTERRUPT_CB
00478 static int default_interrupt_cb(void)
00479 {
00480     return 0;
00481 }
00482 
00483 void avio_set_interrupt_cb(int (*interrupt_cb)(void))
00484 {
00485     if (!interrupt_cb)
00486         interrupt_cb = default_interrupt_cb;
00487     url_interrupt_cb = interrupt_cb;
00488 }
00489 #endif
00490 
00491 int ff_check_interrupt(AVIOInterruptCB *cb)
00492 {
00493     int ret;
00494     if (cb && cb->callback && (ret = cb->callback(cb->opaque)))
00495         return ret;
00496 #if FF_API_OLD_INTERRUPT_CB
00497     return url_interrupt_cb();
00498 #else
00499     return 0;
00500 #endif
00501 }
00502 
00503 #if FF_API_OLD_AVIO
00504 int av_url_read_pause(URLContext *h, int pause)
00505 {
00506     if (!h->prot->url_read_pause)
00507         return AVERROR(ENOSYS);
00508     return h->prot->url_read_pause(h, pause);
00509 }
00510 
00511 int64_t av_url_read_seek(URLContext *h,
00512         int stream_index, int64_t timestamp, int flags)
00513 {
00514     if (!h->prot->url_read_seek)
00515         return AVERROR(ENOSYS);
00516     return h->prot->url_read_seek(h, stream_index, timestamp, flags);
00517 }
00518 #endif