annotate ffmpeg/libavformat/avio.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * unbuffered I/O
yading@11 3 * Copyright (c) 2001 Fabrice Bellard
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 #include "libavutil/avstring.h"
yading@11 23 #include "libavutil/dict.h"
yading@11 24 #include "libavutil/opt.h"
yading@11 25 #include "libavutil/time.h"
yading@11 26 #include "os_support.h"
yading@11 27 #include "avformat.h"
yading@11 28 #if CONFIG_NETWORK
yading@11 29 #include "network.h"
yading@11 30 #endif
yading@11 31 #include "url.h"
yading@11 32
yading@11 33 static URLProtocol *first_protocol = NULL;
yading@11 34
yading@11 35 URLProtocol *ffurl_protocol_next(URLProtocol *prev)
yading@11 36 {
yading@11 37 return prev ? prev->next : first_protocol;
yading@11 38 }
yading@11 39
yading@11 40 /** @name Logging context. */
yading@11 41 /*@{*/
yading@11 42 static const char *urlcontext_to_name(void *ptr)
yading@11 43 {
yading@11 44 URLContext *h = (URLContext *)ptr;
yading@11 45 if(h->prot) return h->prot->name;
yading@11 46 else return "NULL";
yading@11 47 }
yading@11 48
yading@11 49 static void *urlcontext_child_next(void *obj, void *prev)
yading@11 50 {
yading@11 51 URLContext *h = obj;
yading@11 52 if (!prev && h->priv_data && h->prot->priv_data_class)
yading@11 53 return h->priv_data;
yading@11 54 return NULL;
yading@11 55 }
yading@11 56
yading@11 57 static const AVClass *urlcontext_child_class_next(const AVClass *prev)
yading@11 58 {
yading@11 59 URLProtocol *p = NULL;
yading@11 60
yading@11 61 /* find the protocol that corresponds to prev */
yading@11 62 while (prev && (p = ffurl_protocol_next(p)))
yading@11 63 if (p->priv_data_class == prev)
yading@11 64 break;
yading@11 65
yading@11 66 /* find next protocol with priv options */
yading@11 67 while (p = ffurl_protocol_next(p))
yading@11 68 if (p->priv_data_class)
yading@11 69 return p->priv_data_class;
yading@11 70 return NULL;
yading@11 71
yading@11 72 }
yading@11 73
yading@11 74 static const AVOption options[] = {{NULL}};
yading@11 75 const AVClass ffurl_context_class = {
yading@11 76 .class_name = "URLContext",
yading@11 77 .item_name = urlcontext_to_name,
yading@11 78 .option = options,
yading@11 79 .version = LIBAVUTIL_VERSION_INT,
yading@11 80 .child_next = urlcontext_child_next,
yading@11 81 .child_class_next = urlcontext_child_class_next,
yading@11 82 };
yading@11 83 /*@}*/
yading@11 84
yading@11 85
yading@11 86 const char *avio_enum_protocols(void **opaque, int output)
yading@11 87 {
yading@11 88 URLProtocol *p;
yading@11 89 *opaque = ffurl_protocol_next(*opaque);
yading@11 90 if (!(p = *opaque)) return NULL;
yading@11 91 if ((output && p->url_write) || (!output && p->url_read))
yading@11 92 return p->name;
yading@11 93 return avio_enum_protocols(opaque, output);
yading@11 94 }
yading@11 95
yading@11 96 int ffurl_register_protocol(URLProtocol *protocol, int size)
yading@11 97 {
yading@11 98 URLProtocol **p;
yading@11 99 if (size < sizeof(URLProtocol)) {
yading@11 100 URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
yading@11 101 memcpy(temp, protocol, size);
yading@11 102 protocol = temp;
yading@11 103 }
yading@11 104 p = &first_protocol;
yading@11 105 while (*p != NULL) p = &(*p)->next;
yading@11 106 *p = protocol;
yading@11 107 protocol->next = NULL;
yading@11 108 return 0;
yading@11 109 }
yading@11 110
yading@11 111 static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
yading@11 112 const char *filename, int flags,
yading@11 113 const AVIOInterruptCB *int_cb)
yading@11 114 {
yading@11 115 URLContext *uc;
yading@11 116 int err;
yading@11 117
yading@11 118 #if CONFIG_NETWORK
yading@11 119 if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init())
yading@11 120 return AVERROR(EIO);
yading@11 121 #endif
yading@11 122 if ((flags & AVIO_FLAG_READ) && !up->url_read) {
yading@11 123 av_log(NULL, AV_LOG_ERROR,
yading@11 124 "Impossible to open the '%s' protocol for reading\n", up->name);
yading@11 125 return AVERROR(EIO);
yading@11 126 }
yading@11 127 if ((flags & AVIO_FLAG_WRITE) && !up->url_write) {
yading@11 128 av_log(NULL, AV_LOG_ERROR,
yading@11 129 "Impossible to open the '%s' protocol for writing\n", up->name);
yading@11 130 return AVERROR(EIO);
yading@11 131 }
yading@11 132 uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
yading@11 133 if (!uc) {
yading@11 134 err = AVERROR(ENOMEM);
yading@11 135 goto fail;
yading@11 136 }
yading@11 137 uc->av_class = &ffurl_context_class;
yading@11 138 uc->filename = (char *) &uc[1];
yading@11 139 strcpy(uc->filename, filename);
yading@11 140 uc->prot = up;
yading@11 141 uc->flags = flags;
yading@11 142 uc->is_streamed = 0; /* default = not streamed */
yading@11 143 uc->max_packet_size = 0; /* default: stream file */
yading@11 144 if (up->priv_data_size) {
yading@11 145 uc->priv_data = av_mallocz(up->priv_data_size);
yading@11 146 if (up->priv_data_class) {
yading@11 147 int proto_len= strlen(up->name);
yading@11 148 char *start = strchr(uc->filename, ',');
yading@11 149 *(const AVClass**)uc->priv_data = up->priv_data_class;
yading@11 150 av_opt_set_defaults(uc->priv_data);
yading@11 151 if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){
yading@11 152 int ret= 0;
yading@11 153 char *p= start;
yading@11 154 char sep= *++p;
yading@11 155 char *key, *val;
yading@11 156 p++;
yading@11 157 while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){
yading@11 158 *val= *key= 0;
yading@11 159 ret= av_opt_set(uc->priv_data, p, key+1, 0);
yading@11 160 if (ret == AVERROR_OPTION_NOT_FOUND)
yading@11 161 av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p);
yading@11 162 *val= *key= sep;
yading@11 163 p= val+1;
yading@11 164 }
yading@11 165 if(ret<0 || p!=key){
yading@11 166 av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start);
yading@11 167 av_freep(&uc->priv_data);
yading@11 168 av_freep(&uc);
yading@11 169 err = AVERROR(EINVAL);
yading@11 170 goto fail;
yading@11 171 }
yading@11 172 memmove(start, key+1, strlen(key));
yading@11 173 }
yading@11 174 }
yading@11 175 }
yading@11 176 if (int_cb)
yading@11 177 uc->interrupt_callback = *int_cb;
yading@11 178
yading@11 179 *puc = uc;
yading@11 180 return 0;
yading@11 181 fail:
yading@11 182 *puc = NULL;
yading@11 183 #if CONFIG_NETWORK
yading@11 184 if (up->flags & URL_PROTOCOL_FLAG_NETWORK)
yading@11 185 ff_network_close();
yading@11 186 #endif
yading@11 187 return err;
yading@11 188 }
yading@11 189
yading@11 190 int ffurl_connect(URLContext* uc, AVDictionary **options)
yading@11 191 {
yading@11 192 int err =
yading@11 193 uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
yading@11 194 uc->prot->url_open(uc, uc->filename, uc->flags);
yading@11 195 if (err)
yading@11 196 return err;
yading@11 197 uc->is_connected = 1;
yading@11 198 //We must be careful here as ffurl_seek() could be slow, for example for http
yading@11 199 if( (uc->flags & AVIO_FLAG_WRITE)
yading@11 200 || !strcmp(uc->prot->name, "file"))
yading@11 201 if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
yading@11 202 uc->is_streamed= 1;
yading@11 203 return 0;
yading@11 204 }
yading@11 205
yading@11 206 #define URL_SCHEME_CHARS \
yading@11 207 "abcdefghijklmnopqrstuvwxyz" \
yading@11 208 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
yading@11 209 "0123456789+-."
yading@11 210
yading@11 211 int ffurl_alloc(URLContext **puc, const char *filename, int flags,
yading@11 212 const AVIOInterruptCB *int_cb)
yading@11 213 {
yading@11 214 URLProtocol *up = NULL;
yading@11 215 char proto_str[128], proto_nested[128], *ptr;
yading@11 216 size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
yading@11 217
yading@11 218 if (!first_protocol) {
yading@11 219 av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. "
yading@11 220 "Missing call to av_register_all()?\n");
yading@11 221 }
yading@11 222
yading@11 223 if (filename[proto_len] != ':' &&
yading@11 224 (filename[proto_len] != ',' || !strchr(filename + proto_len + 1, ':')) ||
yading@11 225 is_dos_path(filename))
yading@11 226 strcpy(proto_str, "file");
yading@11 227 else
yading@11 228 av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str)));
yading@11 229
yading@11 230 if ((ptr = strchr(proto_str, ',')))
yading@11 231 *ptr = '\0';
yading@11 232 av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
yading@11 233 if ((ptr = strchr(proto_nested, '+')))
yading@11 234 *ptr = '\0';
yading@11 235
yading@11 236 while (up = ffurl_protocol_next(up)) {
yading@11 237 if (!strcmp(proto_str, up->name))
yading@11 238 return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
yading@11 239 if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
yading@11 240 !strcmp(proto_nested, up->name))
yading@11 241 return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
yading@11 242 }
yading@11 243 *puc = NULL;
yading@11 244 return AVERROR_PROTOCOL_NOT_FOUND;
yading@11 245 }
yading@11 246
yading@11 247 int ffurl_open(URLContext **puc, const char *filename, int flags,
yading@11 248 const AVIOInterruptCB *int_cb, AVDictionary **options)
yading@11 249 {
yading@11 250 int ret = ffurl_alloc(puc, filename, flags, int_cb);
yading@11 251 if (ret)
yading@11 252 return ret;
yading@11 253 if (options && (*puc)->prot->priv_data_class &&
yading@11 254 (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
yading@11 255 goto fail;
yading@11 256 ret = ffurl_connect(*puc, options);
yading@11 257 if (!ret)
yading@11 258 return 0;
yading@11 259 fail:
yading@11 260 ffurl_close(*puc);
yading@11 261 *puc = NULL;
yading@11 262 return ret;
yading@11 263 }
yading@11 264
yading@11 265 static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min,
yading@11 266 int (*transfer_func)(URLContext *h, unsigned char *buf, int size))
yading@11 267 {
yading@11 268 int ret, len;
yading@11 269 int fast_retries = 5;
yading@11 270 int64_t wait_since = 0;
yading@11 271
yading@11 272 len = 0;
yading@11 273 while (len < size_min) {
yading@11 274 ret = transfer_func(h, buf+len, size-len);
yading@11 275 if (ret == AVERROR(EINTR))
yading@11 276 continue;
yading@11 277 if (h->flags & AVIO_FLAG_NONBLOCK)
yading@11 278 return ret;
yading@11 279 if (ret == AVERROR(EAGAIN)) {
yading@11 280 ret = 0;
yading@11 281 if (fast_retries) {
yading@11 282 fast_retries--;
yading@11 283 } else {
yading@11 284 if (h->rw_timeout) {
yading@11 285 if (!wait_since)
yading@11 286 wait_since = av_gettime();
yading@11 287 else if (av_gettime() > wait_since + h->rw_timeout)
yading@11 288 return AVERROR(EIO);
yading@11 289 }
yading@11 290 av_usleep(1000);
yading@11 291 }
yading@11 292 } else if (ret < 1)
yading@11 293 return ret < 0 ? ret : len;
yading@11 294 if (ret)
yading@11 295 fast_retries = FFMAX(fast_retries, 2);
yading@11 296 len += ret;
yading@11 297 if (len < size && ff_check_interrupt(&h->interrupt_callback))
yading@11 298 return AVERROR_EXIT;
yading@11 299 }
yading@11 300 return len;
yading@11 301 }
yading@11 302
yading@11 303 int ffurl_read(URLContext *h, unsigned char *buf, int size)
yading@11 304 {
yading@11 305 if (!(h->flags & AVIO_FLAG_READ))
yading@11 306 return AVERROR(EIO);
yading@11 307 return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);
yading@11 308 }
yading@11 309
yading@11 310 int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
yading@11 311 {
yading@11 312 if (!(h->flags & AVIO_FLAG_READ))
yading@11 313 return AVERROR(EIO);
yading@11 314 return retry_transfer_wrapper(h, buf, size, size, h->prot->url_read);
yading@11 315 }
yading@11 316
yading@11 317 int ffurl_write(URLContext *h, const unsigned char *buf, int size)
yading@11 318 {
yading@11 319 if (!(h->flags & AVIO_FLAG_WRITE))
yading@11 320 return AVERROR(EIO);
yading@11 321 /* avoid sending too big packets */
yading@11 322 if (h->max_packet_size && size > h->max_packet_size)
yading@11 323 return AVERROR(EIO);
yading@11 324
yading@11 325 return retry_transfer_wrapper(h, (unsigned char *)buf, size, size, (void*)h->prot->url_write);
yading@11 326 }
yading@11 327
yading@11 328 int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
yading@11 329 {
yading@11 330 int64_t ret;
yading@11 331
yading@11 332 if (!h->prot->url_seek)
yading@11 333 return AVERROR(ENOSYS);
yading@11 334 ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
yading@11 335 return ret;
yading@11 336 }
yading@11 337
yading@11 338 int ffurl_closep(URLContext **hh)
yading@11 339 {
yading@11 340 URLContext *h= *hh;
yading@11 341 int ret = 0;
yading@11 342 if (!h) return 0; /* can happen when ffurl_open fails */
yading@11 343
yading@11 344 if (h->is_connected && h->prot->url_close)
yading@11 345 ret = h->prot->url_close(h);
yading@11 346 #if CONFIG_NETWORK
yading@11 347 if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)
yading@11 348 ff_network_close();
yading@11 349 #endif
yading@11 350 if (h->prot->priv_data_size) {
yading@11 351 if (h->prot->priv_data_class)
yading@11 352 av_opt_free(h->priv_data);
yading@11 353 av_freep(&h->priv_data);
yading@11 354 }
yading@11 355 av_freep(hh);
yading@11 356 return ret;
yading@11 357 }
yading@11 358
yading@11 359 int ffurl_close(URLContext *h)
yading@11 360 {
yading@11 361 return ffurl_closep(&h);
yading@11 362 }
yading@11 363
yading@11 364
yading@11 365 int avio_check(const char *url, int flags)
yading@11 366 {
yading@11 367 URLContext *h;
yading@11 368 int ret = ffurl_alloc(&h, url, flags, NULL);
yading@11 369 if (ret)
yading@11 370 return ret;
yading@11 371
yading@11 372 if (h->prot->url_check) {
yading@11 373 ret = h->prot->url_check(h, flags);
yading@11 374 } else {
yading@11 375 ret = ffurl_connect(h, NULL);
yading@11 376 if (ret >= 0)
yading@11 377 ret = flags;
yading@11 378 }
yading@11 379
yading@11 380 ffurl_close(h);
yading@11 381 return ret;
yading@11 382 }
yading@11 383
yading@11 384 int64_t ffurl_size(URLContext *h)
yading@11 385 {
yading@11 386 int64_t pos, size;
yading@11 387
yading@11 388 size= ffurl_seek(h, 0, AVSEEK_SIZE);
yading@11 389 if(size<0){
yading@11 390 pos = ffurl_seek(h, 0, SEEK_CUR);
yading@11 391 if ((size = ffurl_seek(h, -1, SEEK_END)) < 0)
yading@11 392 return size;
yading@11 393 size++;
yading@11 394 ffurl_seek(h, pos, SEEK_SET);
yading@11 395 }
yading@11 396 return size;
yading@11 397 }
yading@11 398
yading@11 399 int ffurl_get_file_handle(URLContext *h)
yading@11 400 {
yading@11 401 if (!h->prot->url_get_file_handle)
yading@11 402 return -1;
yading@11 403 return h->prot->url_get_file_handle(h);
yading@11 404 }
yading@11 405
yading@11 406 int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles)
yading@11 407 {
yading@11 408 if (!h->prot->url_get_multi_file_handle) {
yading@11 409 if (!h->prot->url_get_file_handle)
yading@11 410 return AVERROR(ENOSYS);
yading@11 411 *handles = av_malloc(sizeof(**handles));
yading@11 412 if (!*handles)
yading@11 413 return AVERROR(ENOMEM);
yading@11 414 *numhandles = 1;
yading@11 415 *handles[0] = h->prot->url_get_file_handle(h);
yading@11 416 return 0;
yading@11 417 }
yading@11 418 return h->prot->url_get_multi_file_handle(h, handles, numhandles);
yading@11 419 }
yading@11 420
yading@11 421 int ffurl_shutdown(URLContext *h, int flags)
yading@11 422 {
yading@11 423 if (!h->prot->url_shutdown)
yading@11 424 return AVERROR(EINVAL);
yading@11 425 return h->prot->url_shutdown(h, flags);
yading@11 426 }
yading@11 427
yading@11 428 int ff_check_interrupt(AVIOInterruptCB *cb)
yading@11 429 {
yading@11 430 int ret;
yading@11 431 if (cb && cb->callback && (ret = cb->callback(cb->opaque)))
yading@11 432 return ret;
yading@11 433 return 0;
yading@11 434 }