• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavformat/avio.c

Go to the documentation of this file.
00001 /*
00002  * Unbuffered io for ffmpeg system
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/opt.h"
00026 #include "os_support.h"
00027 #include "avformat.h"
00028 #if CONFIG_NETWORK
00029 #include "network.h"
00030 #endif
00031 #include "url.h"
00032 
00033 #if FF_API_URL_CLASS
00034 
00036 static const char *urlcontext_to_name(void *ptr)
00037 {
00038     URLContext *h = (URLContext *)ptr;
00039     if(h->prot) return h->prot->name;
00040     else        return "NULL";
00041 }
00042 static const AVOption options[] = {{NULL}};
00043 static const AVClass urlcontext_class = {
00044     .class_name     = "URLContext",
00045     .item_name      = urlcontext_to_name,
00046     .option         = options,
00047     .version        = LIBAVUTIL_VERSION_INT,
00048 };
00050 #endif
00051 
00052 static int default_interrupt_cb(void);
00053 
00054 URLProtocol *first_protocol = NULL;
00055 int (*url_interrupt_cb)(void) = default_interrupt_cb;
00056 
00057 URLProtocol *av_protocol_next(URLProtocol *p)
00058 {
00059     if(p) return p->next;
00060     else  return first_protocol;
00061 }
00062 
00063 const char *avio_enum_protocols(void **opaque, int output)
00064 {
00065     URLProtocol *p = *opaque;
00066     p = p ? p->next : first_protocol;
00067     if (!p) return NULL;
00068     if ((output && p->url_write) || (!output && p->url_read))
00069         return p->name;
00070     return avio_enum_protocols(opaque, output);
00071 }
00072 
00073 int ffurl_register_protocol(URLProtocol *protocol, int size)
00074 {
00075     URLProtocol **p;
00076     if (size < sizeof(URLProtocol)) {
00077         URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
00078         memcpy(temp, protocol, size);
00079         protocol = temp;
00080     }
00081     p = &first_protocol;
00082     while (*p != NULL) p = &(*p)->next;
00083     *p = protocol;
00084     protocol->next = NULL;
00085     return 0;
00086 }
00087 
00088 #if FF_API_REGISTER_PROTOCOL
00089 /* The layout of URLProtocol as of when major was bumped to 52 */
00090 struct URLProtocol_compat {
00091     const char *name;
00092     int (*url_open)(URLContext *h, const char *filename, int flags);
00093     int (*url_read)(URLContext *h, unsigned char *buf, int size);
00094     int (*url_write)(URLContext *h, unsigned char *buf, int size);
00095     int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);
00096     int (*url_close)(URLContext *h);
00097     struct URLProtocol *next;
00098 };
00099 
00100 int av_register_protocol(URLProtocol *protocol)
00101 {
00102     return ffurl_register_protocol(protocol, sizeof(struct URLProtocol_compat));
00103 }
00104 
00105 int register_protocol(URLProtocol *protocol)
00106 {
00107     return ffurl_register_protocol(protocol, sizeof(struct URLProtocol_compat));
00108 }
00109 #endif
00110 
00111 static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
00112                                    const char *filename, int flags)
00113 {
00114     URLContext *uc;
00115     int err;
00116 
00117 #if CONFIG_NETWORK
00118     if (!ff_network_init())
00119         return AVERROR(EIO);
00120 #endif
00121     uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
00122     if (!uc) {
00123         err = AVERROR(ENOMEM);
00124         goto fail;
00125     }
00126 #if FF_API_URL_CLASS
00127     uc->av_class = &urlcontext_class;
00128 #endif
00129     uc->filename = (char *) &uc[1];
00130     strcpy(uc->filename, filename);
00131     uc->prot = up;
00132     uc->flags = flags;
00133     uc->is_streamed = 0; /* default = not streamed */
00134     uc->max_packet_size = 0; /* default: stream file */
00135     if (up->priv_data_size) {
00136         uc->priv_data = av_mallocz(up->priv_data_size);
00137         if (up->priv_data_class) {
00138             *(const AVClass**)uc->priv_data = up->priv_data_class;
00139             av_opt_set_defaults(uc->priv_data);
00140         }
00141     }
00142 
00143     *puc = uc;
00144     return 0;
00145  fail:
00146     *puc = NULL;
00147 #if CONFIG_NETWORK
00148     ff_network_close();
00149 #endif
00150     return err;
00151 }
00152 
00153 int ffurl_connect(URLContext* uc)
00154 {
00155     int err = uc->prot->url_open(uc, uc->filename, uc->flags);
00156     if (err)
00157         return err;
00158     uc->is_connected = 1;
00159     //We must be careful here as ffurl_seek() could be slow, for example for http
00160     if(   (uc->flags & (AVIO_WRONLY | AVIO_RDWR))
00161        || !strcmp(uc->prot->name, "file"))
00162         if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
00163             uc->is_streamed= 1;
00164     return 0;
00165 }
00166 
00167 #if FF_API_OLD_AVIO
00168 int url_open_protocol (URLContext **puc, struct URLProtocol *up,
00169                        const char *filename, int flags)
00170 {
00171     int ret;
00172 
00173     ret = url_alloc_for_protocol(puc, up, filename, flags);
00174     if (ret)
00175         goto fail;
00176     ret = ffurl_connect(*puc);
00177     if (!ret)
00178         return 0;
00179  fail:
00180     ffurl_close(*puc);
00181     *puc = NULL;
00182     return ret;
00183 }
00184 int url_alloc(URLContext **puc, const char *filename, int flags)
00185 {
00186     return ffurl_alloc(puc, filename, flags);
00187 }
00188 int url_connect(URLContext* uc)
00189 {
00190     return ffurl_connect(uc);
00191 }
00192 int url_open(URLContext **puc, const char *filename, int flags)
00193 {
00194     return ffurl_open(puc, filename, flags);
00195 }
00196 int url_read(URLContext *h, unsigned char *buf, int size)
00197 {
00198     return ffurl_read(h, buf, size);
00199 }
00200 int url_read_complete(URLContext *h, unsigned char *buf, int size)
00201 {
00202     return ffurl_read_complete(h, buf, size);
00203 }
00204 int url_write(URLContext *h, const unsigned char *buf, int size)
00205 {
00206     return ffurl_write(h, buf, size);
00207 }
00208 int64_t url_seek(URLContext *h, int64_t pos, int whence)
00209 {
00210     return ffurl_seek(h, pos, whence);
00211 }
00212 int url_close(URLContext *h)
00213 {
00214     return ffurl_close(h);
00215 }
00216 int64_t url_filesize(URLContext *h)
00217 {
00218     return ffurl_size(h);
00219 }
00220 int url_get_file_handle(URLContext *h)
00221 {
00222     return ffurl_get_file_handle(h);
00223 }
00224 int url_get_max_packet_size(URLContext *h)
00225 {
00226     return h->max_packet_size;
00227 }
00228 void url_get_filename(URLContext *h, char *buf, int buf_size)
00229 {
00230     av_strlcpy(buf, h->filename, buf_size);
00231 }
00232 void url_set_interrupt_cb(URLInterruptCB *interrupt_cb)
00233 {
00234     avio_set_interrupt_cb(interrupt_cb);
00235 }
00236 int av_register_protocol2(URLProtocol *protocol, int size)
00237 {
00238     return ffurl_register_protocol(protocol, size);
00239 }
00240 #endif
00241 
00242 #define URL_SCHEME_CHARS                        \
00243     "abcdefghijklmnopqrstuvwxyz"                \
00244     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                \
00245     "0123456789+-."
00246 
00247 int ffurl_alloc(URLContext **puc, const char *filename, int flags)
00248 {
00249     URLProtocol *up;
00250     char proto_str[128], proto_nested[128], *ptr;
00251     size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
00252 
00253     if (filename[proto_len] != ':' || is_dos_path(filename))
00254         strcpy(proto_str, "file");
00255     else
00256         av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str)));
00257 
00258     av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
00259     if ((ptr = strchr(proto_nested, '+')))
00260         *ptr = '\0';
00261 
00262     up = first_protocol;
00263     while (up != NULL) {
00264         if (!strcmp(proto_str, up->name))
00265             return url_alloc_for_protocol (puc, up, filename, flags);
00266         if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
00267             !strcmp(proto_nested, up->name))
00268             return url_alloc_for_protocol (puc, up, filename, flags);
00269         up = up->next;
00270     }
00271     *puc = NULL;
00272     return AVERROR(ENOENT);
00273 }
00274 
00275 int ffurl_open(URLContext **puc, const char *filename, int flags)
00276 {
00277     int ret = ffurl_alloc(puc, filename, flags);
00278     if (ret)
00279         return ret;
00280     ret = ffurl_connect(*puc);
00281     if (!ret)
00282         return 0;
00283     ffurl_close(*puc);
00284     *puc = NULL;
00285     return ret;
00286 }
00287 
00288 static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min,
00289                                          int (*transfer_func)(URLContext *h, unsigned char *buf, int size))
00290 {
00291     int ret, len;
00292     int fast_retries = 5;
00293 
00294     len = 0;
00295     while (len < size_min) {
00296         ret = transfer_func(h, buf+len, size-len);
00297         if (ret == AVERROR(EINTR))
00298             continue;
00299         if (h->flags & AVIO_FLAG_NONBLOCK)
00300             return ret;
00301         if (ret == AVERROR(EAGAIN)) {
00302             ret = 0;
00303             if (fast_retries)
00304                 fast_retries--;
00305             else
00306                 usleep(1000);
00307         } else if (ret < 1)
00308             return ret < 0 ? ret : len;
00309         if (ret)
00310            fast_retries = FFMAX(fast_retries, 2);
00311         len += ret;
00312         if (len < size && url_interrupt_cb())
00313             return AVERROR_EXIT;
00314     }
00315     return len;
00316 }
00317 
00318 int ffurl_read(URLContext *h, unsigned char *buf, int size)
00319 {
00320     if (h->flags & AVIO_WRONLY)
00321         return AVERROR(EIO);
00322     return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);
00323 }
00324 
00325 int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
00326 {
00327     if (h->flags & AVIO_WRONLY)
00328         return AVERROR(EIO);
00329     return retry_transfer_wrapper(h, buf, size, size, h->prot->url_read);
00330 }
00331 
00332 int ffurl_write(URLContext *h, const unsigned char *buf, int size)
00333 {
00334     if (!(h->flags & (AVIO_WRONLY | AVIO_RDWR)))
00335         return AVERROR(EIO);
00336     /* avoid sending too big packets */
00337     if (h->max_packet_size && size > h->max_packet_size)
00338         return AVERROR(EIO);
00339 
00340     return retry_transfer_wrapper(h, buf, size, size, (void*)h->prot->url_write);
00341 }
00342 
00343 int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
00344 {
00345     int64_t ret;
00346 
00347     if (!h->prot->url_seek)
00348         return AVERROR(ENOSYS);
00349     ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
00350     return ret;
00351 }
00352 
00353 int ffurl_close(URLContext *h)
00354 {
00355     int ret = 0;
00356     if (!h) return 0; /* can happen when ffurl_open fails */
00357 
00358     if (h->is_connected && h->prot->url_close)
00359         ret = h->prot->url_close(h);
00360 #if CONFIG_NETWORK
00361     ff_network_close();
00362 #endif
00363     if (h->prot->priv_data_size)
00364         av_free(h->priv_data);
00365     av_free(h);
00366     return ret;
00367 }
00368 
00369 #if FF_API_OLD_AVIO
00370 int url_exist(const char *filename)
00371 {
00372     URLContext *h;
00373     if (ffurl_open(&h, filename, AVIO_RDONLY) < 0)
00374         return 0;
00375     ffurl_close(h);
00376     return 1;
00377 }
00378 #endif
00379 
00380 int avio_check(const char *url, int flags)
00381 {
00382     URLContext *h;
00383     int ret = ffurl_alloc(&h, url, flags);
00384     if (ret)
00385         return ret;
00386 
00387     if (h->prot->url_check) {
00388         ret = h->prot->url_check(h, flags);
00389     } else {
00390         ret = ffurl_connect(h);
00391         if (ret >= 0)
00392             ret = flags;
00393     }
00394 
00395     ffurl_close(h);
00396     return ret;
00397 }
00398 
00399 int64_t ffurl_size(URLContext *h)
00400 {
00401     int64_t pos, size;
00402 
00403     size= ffurl_seek(h, 0, AVSEEK_SIZE);
00404     if(size<0){
00405         pos = ffurl_seek(h, 0, SEEK_CUR);
00406         if ((size = ffurl_seek(h, -1, SEEK_END)) < 0)
00407             return size;
00408         size++;
00409         ffurl_seek(h, pos, SEEK_SET);
00410     }
00411     return size;
00412 }
00413 
00414 int ffurl_get_file_handle(URLContext *h)
00415 {
00416     if (!h->prot->url_get_file_handle)
00417         return -1;
00418     return h->prot->url_get_file_handle(h);
00419 }
00420 
00421 static int default_interrupt_cb(void)
00422 {
00423     return 0;
00424 }
00425 
00426 void avio_set_interrupt_cb(int (*interrupt_cb)(void))
00427 {
00428     if (!interrupt_cb)
00429         interrupt_cb = default_interrupt_cb;
00430     url_interrupt_cb = interrupt_cb;
00431 }
00432 
00433 #if FF_API_OLD_AVIO
00434 int av_url_read_pause(URLContext *h, int pause)
00435 {
00436     if (!h->prot->url_read_pause)
00437         return AVERROR(ENOSYS);
00438     return h->prot->url_read_pause(h, pause);
00439 }
00440 
00441 int64_t av_url_read_seek(URLContext *h,
00442         int stream_index, int64_t timestamp, int flags)
00443 {
00444     if (!h->prot->url_read_seek)
00445         return AVERROR(ENOSYS);
00446     return h->prot->url_read_seek(h, stream_index, timestamp, flags);
00447 }
00448 #endif

Generated on Fri Feb 22 2013 07:24:31 for FFmpeg by  doxygen 1.7.1