Libav
|
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 /* needed for usleep() */ 00023 #define _XOPEN_SOURCE 600 00024 #include <unistd.h> 00025 #include "libavutil/avstring.h" 00026 #include "libavcodec/opt.h" 00027 #include "os_support.h" 00028 #include "avformat.h" 00029 #if CONFIG_NETWORK 00030 #include "network.h" 00031 #endif 00032 00033 #if LIBAVFORMAT_VERSION_MAJOR >= 53 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 { "URLContext", urlcontext_to_name, options, LIBAVUTIL_VERSION_INT }; 00046 #endif 00047 00048 static int default_interrupt_cb(void); 00049 00050 URLProtocol *first_protocol = NULL; 00051 URLInterruptCB *url_interrupt_cb = default_interrupt_cb; 00052 00053 URLProtocol *av_protocol_next(URLProtocol *p) 00054 { 00055 if(p) return p->next; 00056 else return first_protocol; 00057 } 00058 00059 int av_register_protocol(URLProtocol *protocol) 00060 { 00061 URLProtocol **p; 00062 p = &first_protocol; 00063 while (*p != NULL) p = &(*p)->next; 00064 *p = protocol; 00065 protocol->next = NULL; 00066 return 0; 00067 } 00068 00069 #if LIBAVFORMAT_VERSION_MAJOR < 53 00070 int register_protocol(URLProtocol *protocol) 00071 { 00072 return av_register_protocol(protocol); 00073 } 00074 #endif 00075 00076 int url_open_protocol (URLContext **puc, struct URLProtocol *up, 00077 const char *filename, int flags) 00078 { 00079 URLContext *uc; 00080 int err; 00081 00082 #if CONFIG_NETWORK 00083 if (!ff_network_init()) 00084 return AVERROR(EIO); 00085 #endif 00086 uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); 00087 if (!uc) { 00088 err = AVERROR(ENOMEM); 00089 goto fail; 00090 } 00091 #if LIBAVFORMAT_VERSION_MAJOR >= 53 00092 uc->av_class = &urlcontext_class; 00093 #endif 00094 uc->filename = (char *) &uc[1]; 00095 strcpy(uc->filename, filename); 00096 uc->prot = up; 00097 uc->flags = flags; 00098 uc->is_streamed = 0; /* default = not streamed */ 00099 uc->max_packet_size = 0; /* default: stream file */ 00100 err = up->url_open(uc, filename, flags); 00101 if (err < 0) { 00102 av_free(uc); 00103 goto fail; 00104 } 00105 00106 //We must be careful here as url_seek() could be slow, for example for http 00107 if( (flags & (URL_WRONLY | URL_RDWR)) 00108 || !strcmp(up->name, "file")) 00109 if(!uc->is_streamed && url_seek(uc, 0, SEEK_SET) < 0) 00110 uc->is_streamed= 1; 00111 *puc = uc; 00112 return 0; 00113 fail: 00114 *puc = NULL; 00115 #if CONFIG_NETWORK 00116 ff_network_close(); 00117 #endif 00118 return err; 00119 } 00120 00121 int url_open(URLContext **puc, const char *filename, int flags) 00122 { 00123 URLProtocol *up; 00124 const char *p; 00125 char proto_str[128], *q; 00126 00127 p = filename; 00128 q = proto_str; 00129 while (*p != '\0' && *p != ':') { 00130 /* protocols can only contain alphabetic chars */ 00131 if (!isalpha(*p)) 00132 goto file_proto; 00133 if ((q - proto_str) < sizeof(proto_str) - 1) 00134 *q++ = *p; 00135 p++; 00136 } 00137 /* if the protocol has length 1, we consider it is a dos drive */ 00138 if (*p == '\0' || is_dos_path(filename)) { 00139 file_proto: 00140 strcpy(proto_str, "file"); 00141 } else { 00142 *q = '\0'; 00143 } 00144 00145 up = first_protocol; 00146 while (up != NULL) { 00147 if (!strcmp(proto_str, up->name)) 00148 return url_open_protocol (puc, up, filename, flags); 00149 up = up->next; 00150 } 00151 *puc = NULL; 00152 return AVERROR(ENOENT); 00153 } 00154 00155 int url_read(URLContext *h, unsigned char *buf, int size) 00156 { 00157 int ret; 00158 if (h->flags & URL_WRONLY) 00159 return AVERROR(EIO); 00160 ret = h->prot->url_read(h, buf, size); 00161 return ret; 00162 } 00163 00164 int url_read_complete(URLContext *h, unsigned char *buf, int size) 00165 { 00166 int ret, len; 00167 int fast_retries = 5; 00168 00169 len = 0; 00170 while (len < size) { 00171 ret = url_read(h, buf+len, size-len); 00172 if (ret == AVERROR(EAGAIN)) { 00173 ret = 0; 00174 if (fast_retries) 00175 fast_retries--; 00176 else 00177 usleep(1000); 00178 } else if (ret < 1) 00179 return ret < 0 ? ret : len; 00180 if (ret) 00181 fast_retries = FFMAX(fast_retries, 2); 00182 len += ret; 00183 } 00184 return len; 00185 } 00186 00187 int url_write(URLContext *h, unsigned char *buf, int size) 00188 { 00189 int ret; 00190 if (!(h->flags & (URL_WRONLY | URL_RDWR))) 00191 return AVERROR(EIO); 00192 /* avoid sending too big packets */ 00193 if (h->max_packet_size && size > h->max_packet_size) 00194 return AVERROR(EIO); 00195 ret = h->prot->url_write(h, buf, size); 00196 return ret; 00197 } 00198 00199 int64_t url_seek(URLContext *h, int64_t pos, int whence) 00200 { 00201 int64_t ret; 00202 00203 if (!h->prot->url_seek) 00204 return AVERROR(ENOSYS); 00205 ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE); 00206 return ret; 00207 } 00208 00209 int url_close(URLContext *h) 00210 { 00211 int ret = 0; 00212 if (!h) return 0; /* can happen when url_open fails */ 00213 00214 if (h->prot->url_close) 00215 ret = h->prot->url_close(h); 00216 #if CONFIG_NETWORK 00217 ff_network_close(); 00218 #endif 00219 av_free(h); 00220 return ret; 00221 } 00222 00223 int url_exist(const char *filename) 00224 { 00225 URLContext *h; 00226 if (url_open(&h, filename, URL_RDONLY) < 0) 00227 return 0; 00228 url_close(h); 00229 return 1; 00230 } 00231 00232 int64_t url_filesize(URLContext *h) 00233 { 00234 int64_t pos, size; 00235 00236 size= url_seek(h, 0, AVSEEK_SIZE); 00237 if(size<0){ 00238 pos = url_seek(h, 0, SEEK_CUR); 00239 if ((size = url_seek(h, -1, SEEK_END)) < 0) 00240 return size; 00241 size++; 00242 url_seek(h, pos, SEEK_SET); 00243 } 00244 return size; 00245 } 00246 00247 int url_get_file_handle(URLContext *h) 00248 { 00249 if (!h->prot->url_get_file_handle) 00250 return -1; 00251 return h->prot->url_get_file_handle(h); 00252 } 00253 00254 int url_get_max_packet_size(URLContext *h) 00255 { 00256 return h->max_packet_size; 00257 } 00258 00259 void url_get_filename(URLContext *h, char *buf, int buf_size) 00260 { 00261 av_strlcpy(buf, h->filename, buf_size); 00262 } 00263 00264 00265 static int default_interrupt_cb(void) 00266 { 00267 return 0; 00268 } 00269 00270 void url_set_interrupt_cb(URLInterruptCB *interrupt_cb) 00271 { 00272 if (!interrupt_cb) 00273 interrupt_cb = default_interrupt_cb; 00274 url_interrupt_cb = interrupt_cb; 00275 } 00276 00277 int av_url_read_pause(URLContext *h, int pause) 00278 { 00279 if (!h->prot->url_read_pause) 00280 return AVERROR(ENOSYS); 00281 return h->prot->url_read_pause(h, pause); 00282 } 00283 00284 int64_t av_url_read_seek(URLContext *h, 00285 int stream_index, int64_t timestamp, int flags) 00286 { 00287 if (!h->prot->url_read_seek) 00288 return AVERROR(ENOSYS); 00289 return h->prot->url_read_seek(h, stream_index, timestamp, flags); 00290 }