You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

490 lines
13KB

  1. /*
  2. * unbuffered I/O
  3. * Copyright (c) 2001 Fabrice Bellard
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav 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. * Libav 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 Libav; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include <unistd.h>
  22. #include "libavutil/avstring.h"
  23. #include "libavutil/dict.h"
  24. #include "libavutil/opt.h"
  25. #include "os_support.h"
  26. #include "avformat.h"
  27. #if CONFIG_NETWORK
  28. #include "network.h"
  29. #endif
  30. #include "url.h"
  31. static URLProtocol *first_protocol = NULL;
  32. URLProtocol *ffurl_protocol_next(URLProtocol *prev)
  33. {
  34. return prev ? prev->next : first_protocol;
  35. }
  36. /** @name Logging context. */
  37. /*@{*/
  38. static const char *urlcontext_to_name(void *ptr)
  39. {
  40. URLContext *h = (URLContext *)ptr;
  41. if(h->prot) return h->prot->name;
  42. else return "NULL";
  43. }
  44. static void *urlcontext_child_next(void *obj, void *prev)
  45. {
  46. URLContext *h = obj;
  47. if (!prev && h->priv_data && h->prot->priv_data_class)
  48. return h->priv_data;
  49. return NULL;
  50. }
  51. static const AVClass *urlcontext_child_class_next(const AVClass *prev)
  52. {
  53. URLProtocol *p = NULL;
  54. /* find the protocol that corresponds to prev */
  55. while (prev && (p = ffurl_protocol_next(p)))
  56. if (p->priv_data_class == prev)
  57. break;
  58. /* find next protocol with priv options */
  59. while (p = ffurl_protocol_next(p))
  60. if (p->priv_data_class)
  61. return p->priv_data_class;
  62. return NULL;
  63. }
  64. static const AVOption options[] = {{NULL}};
  65. const AVClass ffurl_context_class = {
  66. .class_name = "URLContext",
  67. .item_name = urlcontext_to_name,
  68. .option = options,
  69. .version = LIBAVUTIL_VERSION_INT,
  70. .child_next = urlcontext_child_next,
  71. .child_class_next = urlcontext_child_class_next,
  72. };
  73. /*@}*/
  74. #if FF_API_OLD_INTERRUPT_CB
  75. static int default_interrupt_cb(void);
  76. int (*url_interrupt_cb)(void) = default_interrupt_cb;
  77. #endif
  78. #if FF_API_OLD_AVIO
  79. URLProtocol *av_protocol_next(URLProtocol *p)
  80. {
  81. return ffurl_protocol_next(p);
  82. }
  83. #endif
  84. const char *avio_enum_protocols(void **opaque, int output)
  85. {
  86. URLProtocol **p = opaque;
  87. *p = ffurl_protocol_next(*p);
  88. if (!*p) return NULL;
  89. if ((output && (*p)->url_write) || (!output && (*p)->url_read))
  90. return (*p)->name;
  91. return avio_enum_protocols(opaque, output);
  92. }
  93. int ffurl_register_protocol(URLProtocol *protocol, int size)
  94. {
  95. URLProtocol **p;
  96. if (size < sizeof(URLProtocol)) {
  97. URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
  98. memcpy(temp, protocol, size);
  99. protocol = temp;
  100. }
  101. p = &first_protocol;
  102. while (*p != NULL) p = &(*p)->next;
  103. *p = protocol;
  104. protocol->next = NULL;
  105. return 0;
  106. }
  107. static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
  108. const char *filename, int flags,
  109. const AVIOInterruptCB *int_cb)
  110. {
  111. URLContext *uc;
  112. int err;
  113. #if CONFIG_NETWORK
  114. if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init())
  115. return AVERROR(EIO);
  116. #endif
  117. uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
  118. if (!uc) {
  119. err = AVERROR(ENOMEM);
  120. goto fail;
  121. }
  122. uc->av_class = &ffurl_context_class;
  123. uc->filename = (char *) &uc[1];
  124. strcpy(uc->filename, filename);
  125. uc->prot = up;
  126. uc->flags = flags;
  127. uc->is_streamed = 0; /* default = not streamed */
  128. uc->max_packet_size = 0; /* default: stream file */
  129. if (up->priv_data_size) {
  130. uc->priv_data = av_mallocz(up->priv_data_size);
  131. if (up->priv_data_class) {
  132. *(const AVClass**)uc->priv_data = up->priv_data_class;
  133. av_opt_set_defaults(uc->priv_data);
  134. }
  135. }
  136. if (int_cb)
  137. uc->interrupt_callback = *int_cb;
  138. *puc = uc;
  139. return 0;
  140. fail:
  141. *puc = NULL;
  142. #if CONFIG_NETWORK
  143. if (up->flags & URL_PROTOCOL_FLAG_NETWORK)
  144. ff_network_close();
  145. #endif
  146. return err;
  147. }
  148. int ffurl_connect(URLContext* uc, AVDictionary **options)
  149. {
  150. int err =
  151. #if !FF_API_OLD_AVIO
  152. uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
  153. #endif
  154. uc->prot->url_open(uc, uc->filename, uc->flags);
  155. if (err)
  156. return err;
  157. uc->is_connected = 1;
  158. //We must be careful here as ffurl_seek() could be slow, for example for http
  159. if( (uc->flags & AVIO_FLAG_WRITE)
  160. || !strcmp(uc->prot->name, "file"))
  161. if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
  162. uc->is_streamed= 1;
  163. return 0;
  164. }
  165. #if FF_API_OLD_AVIO
  166. int url_open_protocol (URLContext **puc, struct URLProtocol *up,
  167. const char *filename, int flags)
  168. {
  169. int ret;
  170. ret = url_alloc_for_protocol(puc, up, filename, flags, NULL);
  171. if (ret)
  172. goto fail;
  173. ret = ffurl_connect(*puc, NULL);
  174. if (!ret)
  175. return 0;
  176. fail:
  177. ffurl_close(*puc);
  178. *puc = NULL;
  179. return ret;
  180. }
  181. int url_alloc(URLContext **puc, const char *filename, int flags)
  182. {
  183. return ffurl_alloc(puc, filename, flags, NULL);
  184. }
  185. int url_connect(URLContext* uc)
  186. {
  187. return ffurl_connect(uc, NULL);
  188. }
  189. int url_open(URLContext **puc, const char *filename, int flags)
  190. {
  191. return ffurl_open(puc, filename, flags, NULL, NULL);
  192. }
  193. int url_read(URLContext *h, unsigned char *buf, int size)
  194. {
  195. return ffurl_read(h, buf, size);
  196. }
  197. int url_read_complete(URLContext *h, unsigned char *buf, int size)
  198. {
  199. return ffurl_read_complete(h, buf, size);
  200. }
  201. int url_write(URLContext *h, const unsigned char *buf, int size)
  202. {
  203. return ffurl_write(h, buf, size);
  204. }
  205. int64_t url_seek(URLContext *h, int64_t pos, int whence)
  206. {
  207. return ffurl_seek(h, pos, whence);
  208. }
  209. int url_close(URLContext *h)
  210. {
  211. return ffurl_close(h);
  212. }
  213. int64_t url_filesize(URLContext *h)
  214. {
  215. return ffurl_size(h);
  216. }
  217. int url_get_file_handle(URLContext *h)
  218. {
  219. return ffurl_get_file_handle(h);
  220. }
  221. int url_get_max_packet_size(URLContext *h)
  222. {
  223. return h->max_packet_size;
  224. }
  225. void url_get_filename(URLContext *h, char *buf, int buf_size)
  226. {
  227. av_strlcpy(buf, h->filename, buf_size);
  228. }
  229. void url_set_interrupt_cb(URLInterruptCB *interrupt_cb)
  230. {
  231. avio_set_interrupt_cb(interrupt_cb);
  232. }
  233. int av_register_protocol2(URLProtocol *protocol, int size)
  234. {
  235. return ffurl_register_protocol(protocol, size);
  236. }
  237. #endif
  238. #define URL_SCHEME_CHARS \
  239. "abcdefghijklmnopqrstuvwxyz" \
  240. "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
  241. "0123456789+-."
  242. int ffurl_alloc(URLContext **puc, const char *filename, int flags,
  243. const AVIOInterruptCB *int_cb)
  244. {
  245. URLProtocol *up = NULL;
  246. char proto_str[128], proto_nested[128], *ptr;
  247. size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
  248. if (filename[proto_len] != ':' || is_dos_path(filename))
  249. strcpy(proto_str, "file");
  250. else
  251. av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str)));
  252. av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
  253. if ((ptr = strchr(proto_nested, '+')))
  254. *ptr = '\0';
  255. while (up = ffurl_protocol_next(up)) {
  256. if (!strcmp(proto_str, up->name))
  257. return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
  258. if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
  259. !strcmp(proto_nested, up->name))
  260. return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
  261. }
  262. *puc = NULL;
  263. return AVERROR(ENOENT);
  264. }
  265. int ffurl_open(URLContext **puc, const char *filename, int flags,
  266. const AVIOInterruptCB *int_cb, AVDictionary **options)
  267. {
  268. int ret = ffurl_alloc(puc, filename, flags, int_cb);
  269. if (ret)
  270. return ret;
  271. if (options && (*puc)->prot->priv_data_class &&
  272. (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
  273. goto fail;
  274. ret = ffurl_connect(*puc, options);
  275. if (!ret)
  276. return 0;
  277. fail:
  278. ffurl_close(*puc);
  279. *puc = NULL;
  280. return ret;
  281. }
  282. static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min,
  283. int (*transfer_func)(URLContext *h, unsigned char *buf, int size))
  284. {
  285. int ret, len;
  286. int fast_retries = 5;
  287. len = 0;
  288. while (len < size_min) {
  289. ret = transfer_func(h, buf+len, size-len);
  290. if (ret == AVERROR(EINTR))
  291. continue;
  292. if (h->flags & AVIO_FLAG_NONBLOCK)
  293. return ret;
  294. if (ret == AVERROR(EAGAIN)) {
  295. ret = 0;
  296. if (fast_retries)
  297. fast_retries--;
  298. else
  299. usleep(1000);
  300. } else if (ret < 1)
  301. return ret < 0 ? ret : len;
  302. if (ret)
  303. fast_retries = FFMAX(fast_retries, 2);
  304. len += ret;
  305. if (ff_check_interrupt(&h->interrupt_callback))
  306. return AVERROR_EXIT;
  307. }
  308. return len;
  309. }
  310. int ffurl_read(URLContext *h, unsigned char *buf, int size)
  311. {
  312. if (!(h->flags & AVIO_FLAG_READ))
  313. return AVERROR(EIO);
  314. return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);
  315. }
  316. int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
  317. {
  318. if (!(h->flags & AVIO_FLAG_READ))
  319. return AVERROR(EIO);
  320. return retry_transfer_wrapper(h, buf, size, size, h->prot->url_read);
  321. }
  322. int ffurl_write(URLContext *h, const unsigned char *buf, int size)
  323. {
  324. if (!(h->flags & AVIO_FLAG_WRITE))
  325. return AVERROR(EIO);
  326. /* avoid sending too big packets */
  327. if (h->max_packet_size && size > h->max_packet_size)
  328. return AVERROR(EIO);
  329. return retry_transfer_wrapper(h, buf, size, size, h->prot->url_write);
  330. }
  331. int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
  332. {
  333. int64_t ret;
  334. if (!h->prot->url_seek)
  335. return AVERROR(ENOSYS);
  336. ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
  337. return ret;
  338. }
  339. int ffurl_close(URLContext *h)
  340. {
  341. int ret = 0;
  342. if (!h) return 0; /* can happen when ffurl_open fails */
  343. if (h->is_connected && h->prot->url_close)
  344. ret = h->prot->url_close(h);
  345. #if CONFIG_NETWORK
  346. if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)
  347. ff_network_close();
  348. #endif
  349. if (h->prot->priv_data_size) {
  350. if (h->prot->priv_data_class)
  351. av_opt_free(h->priv_data);
  352. av_free(h->priv_data);
  353. }
  354. av_free(h);
  355. return ret;
  356. }
  357. #if FF_API_OLD_AVIO
  358. int url_exist(const char *filename)
  359. {
  360. URLContext *h;
  361. if (ffurl_open(&h, filename, AVIO_FLAG_READ, NULL, NULL) < 0)
  362. return 0;
  363. ffurl_close(h);
  364. return 1;
  365. }
  366. #endif
  367. int avio_check(const char *url, int flags)
  368. {
  369. URLContext *h;
  370. int ret = ffurl_alloc(&h, url, flags, NULL);
  371. if (ret)
  372. return ret;
  373. if (h->prot->url_check) {
  374. ret = h->prot->url_check(h, flags);
  375. } else {
  376. ret = ffurl_connect(h, NULL);
  377. if (ret >= 0)
  378. ret = flags;
  379. }
  380. ffurl_close(h);
  381. return ret;
  382. }
  383. int64_t ffurl_size(URLContext *h)
  384. {
  385. int64_t pos, size;
  386. size= ffurl_seek(h, 0, AVSEEK_SIZE);
  387. if(size<0){
  388. pos = ffurl_seek(h, 0, SEEK_CUR);
  389. if ((size = ffurl_seek(h, -1, SEEK_END)) < 0)
  390. return size;
  391. size++;
  392. ffurl_seek(h, pos, SEEK_SET);
  393. }
  394. return size;
  395. }
  396. int ffurl_get_file_handle(URLContext *h)
  397. {
  398. if (!h->prot->url_get_file_handle)
  399. return -1;
  400. return h->prot->url_get_file_handle(h);
  401. }
  402. #if FF_API_OLD_INTERRUPT_CB
  403. static int default_interrupt_cb(void)
  404. {
  405. return 0;
  406. }
  407. void avio_set_interrupt_cb(int (*interrupt_cb)(void))
  408. {
  409. if (!interrupt_cb)
  410. interrupt_cb = default_interrupt_cb;
  411. url_interrupt_cb = interrupt_cb;
  412. }
  413. #endif
  414. int ff_check_interrupt(AVIOInterruptCB *cb)
  415. {
  416. int ret;
  417. if (cb && cb->callback && (ret = cb->callback(cb->opaque)))
  418. return ret;
  419. #if FF_API_OLD_INTERRUPT_CB
  420. return url_interrupt_cb();
  421. #else
  422. return 0;
  423. #endif
  424. }
  425. #if FF_API_OLD_AVIO
  426. int av_url_read_pause(URLContext *h, int pause)
  427. {
  428. if (!h->prot->url_read_pause)
  429. return AVERROR(ENOSYS);
  430. return h->prot->url_read_pause(h, pause);
  431. }
  432. int64_t av_url_read_seek(URLContext *h,
  433. int stream_index, int64_t timestamp, int flags)
  434. {
  435. if (!h->prot->url_read_seek)
  436. return AVERROR(ENOSYS);
  437. return h->prot->url_read_seek(h, stream_index, timestamp, flags);
  438. }
  439. #endif