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