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