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