1/* 2 * Unbuffered io for ffmpeg system 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/* needed for usleep() */ 23#define _XOPEN_SOURCE 600 24#include <unistd.h> 25#include "libavutil/avstring.h" 26#include "libavcodec/opt.h" 27#include "os_support.h" 28#include "avformat.h" 29#if CONFIG_NETWORK 30#include "network.h" 31#endif 32 33#if LIBAVFORMAT_VERSION_MAJOR >= 53 34/** @name Logging context. */ 35/*@{*/ 36static const char *urlcontext_to_name(void *ptr) 37{ 38 URLContext *h = (URLContext *)ptr; 39 if(h->prot) return h->prot->name; 40 else return "NULL"; 41} 42static const AVOption options[] = {{NULL}}; 43static const AVClass urlcontext_class = 44 { "URLContext", urlcontext_to_name, options, LIBAVUTIL_VERSION_INT }; 45/*@}*/ 46#endif 47 48static int default_interrupt_cb(void); 49 50URLProtocol *first_protocol = NULL; 51URLInterruptCB *url_interrupt_cb = default_interrupt_cb; 52 53URLProtocol *av_protocol_next(URLProtocol *p) 54{ 55 if(p) return p->next; 56 else return first_protocol; 57} 58 59int av_register_protocol(URLProtocol *protocol) 60{ 61 URLProtocol **p; 62 p = &first_protocol; 63 while (*p != NULL) p = &(*p)->next; 64 *p = protocol; 65 protocol->next = NULL; 66 return 0; 67} 68 69#if LIBAVFORMAT_VERSION_MAJOR < 53 70int register_protocol(URLProtocol *protocol) 71{ 72 return av_register_protocol(protocol); 73} 74#endif 75 76int url_open_protocol (URLContext **puc, struct URLProtocol *up, 77 const char *filename, int flags) 78{ 79 URLContext *uc; 80 int err; 81 82#if CONFIG_NETWORK 83 if (!ff_network_init()) 84 return AVERROR(EIO); 85#endif 86 uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); 87 if (!uc) { 88 err = AVERROR(ENOMEM); 89 goto fail; 90 } 91#if LIBAVFORMAT_VERSION_MAJOR >= 53 92 uc->av_class = &urlcontext_class; 93#endif 94 uc->filename = (char *) &uc[1]; 95 strcpy(uc->filename, filename); 96 uc->prot = up; 97 uc->flags = flags; 98 uc->is_streamed = 0; /* default = not streamed */ 99 uc->max_packet_size = 0; /* default: stream file */ 100 err = up->url_open(uc, filename, flags); 101 if (err < 0) { 102 av_free(uc); 103 goto fail; 104 } 105 106 //We must be careful here as url_seek() could be slow, for example for http 107 if( (flags & (URL_WRONLY | URL_RDWR)) 108 || !strcmp(up->name, "file")) 109 if(!uc->is_streamed && url_seek(uc, 0, SEEK_SET) < 0) 110 uc->is_streamed= 1; 111 *puc = uc; 112 return 0; 113 fail: 114 *puc = NULL; 115#if CONFIG_NETWORK 116 ff_network_close(); 117#endif 118 return err; 119} 120 121int url_open(URLContext **puc, const char *filename, int flags) 122{ 123 URLProtocol *up; 124 const char *p; 125 char proto_str[128], *q; 126 127 p = filename; 128 q = proto_str; 129 while (*p != '\0' && *p != ':') { 130 /* protocols can only contain alphabetic chars */ 131 if (!isalpha(*p)) 132 goto file_proto; 133 if ((q - proto_str) < sizeof(proto_str) - 1) 134 *q++ = *p; 135 p++; 136 } 137 /* if the protocol has length 1, we consider it is a dos drive */ 138 if (*p == '\0' || is_dos_path(filename)) { 139 file_proto: 140 strcpy(proto_str, "file"); 141 } else { 142 *q = '\0'; 143 } 144 145 up = first_protocol; 146 while (up != NULL) { 147 if (!strcmp(proto_str, up->name)) 148 return url_open_protocol (puc, up, filename, flags); 149 up = up->next; 150 } 151 *puc = NULL; 152 return AVERROR(ENOENT); 153} 154 155int url_read(URLContext *h, unsigned char *buf, int size) 156{ 157 int ret; 158 if (h->flags & URL_WRONLY) 159 return AVERROR(EIO); 160 ret = h->prot->url_read(h, buf, size); 161 return ret; 162} 163 164int url_read_complete(URLContext *h, unsigned char *buf, int size) 165{ 166 int ret, len; 167 int fast_retries = 5; 168 169 len = 0; 170 while (len < size) { 171 ret = url_read(h, buf+len, size-len); 172 if (ret == AVERROR(EAGAIN)) { 173 ret = 0; 174 if (fast_retries) 175 fast_retries--; 176 else 177 usleep(1000); 178 } else if (ret < 1) 179 return ret < 0 ? ret : len; 180 if (ret) 181 fast_retries = FFMAX(fast_retries, 2); 182 len += ret; 183 } 184 return len; 185} 186 187int url_write(URLContext *h, unsigned char *buf, int size) 188{ 189 int ret; 190 if (!(h->flags & (URL_WRONLY | URL_RDWR))) 191 return AVERROR(EIO); 192 /* avoid sending too big packets */ 193 if (h->max_packet_size && size > h->max_packet_size) 194 return AVERROR(EIO); 195 ret = h->prot->url_write(h, buf, size); 196 return ret; 197} 198 199int64_t url_seek(URLContext *h, int64_t pos, int whence) 200{ 201 int64_t ret; 202 203 if (!h->prot->url_seek) 204 return AVERROR(ENOSYS); 205 ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE); 206 return ret; 207} 208 209int url_close(URLContext *h) 210{ 211 int ret = 0; 212 if (!h) return 0; /* can happen when url_open fails */ 213 214 if (h->prot->url_close) 215 ret = h->prot->url_close(h); 216#if CONFIG_NETWORK 217 ff_network_close(); 218#endif 219 av_free(h); 220 return ret; 221} 222 223int url_exist(const char *filename) 224{ 225 URLContext *h; 226 if (url_open(&h, filename, URL_RDONLY) < 0) 227 return 0; 228 url_close(h); 229 return 1; 230} 231 232int64_t url_filesize(URLContext *h) 233{ 234 int64_t pos, size; 235 236 size= url_seek(h, 0, AVSEEK_SIZE); 237 if(size<0){ 238 pos = url_seek(h, 0, SEEK_CUR); 239 if ((size = url_seek(h, -1, SEEK_END)) < 0) 240 return size; 241 size++; 242 url_seek(h, pos, SEEK_SET); 243 } 244 return size; 245} 246 247int url_get_file_handle(URLContext *h) 248{ 249 if (!h->prot->url_get_file_handle) 250 return -1; 251 return h->prot->url_get_file_handle(h); 252} 253 254int url_get_max_packet_size(URLContext *h) 255{ 256 return h->max_packet_size; 257} 258 259void url_get_filename(URLContext *h, char *buf, int buf_size) 260{ 261 av_strlcpy(buf, h->filename, buf_size); 262} 263 264 265static int default_interrupt_cb(void) 266{ 267 return 0; 268} 269 270void url_set_interrupt_cb(URLInterruptCB *interrupt_cb) 271{ 272 if (!interrupt_cb) 273 interrupt_cb = default_interrupt_cb; 274 url_interrupt_cb = interrupt_cb; 275} 276 277int av_url_read_pause(URLContext *h, int pause) 278{ 279 if (!h->prot->url_read_pause) 280 return AVERROR(ENOSYS); 281 return h->prot->url_read_pause(h, pause); 282} 283 284int64_t av_url_read_seek(URLContext *h, 285 int stream_index, int64_t timestamp, int flags) 286{ 287 if (!h->prot->url_read_seek) 288 return AVERROR(ENOSYS); 289 return h->prot->url_read_seek(h, stream_index, timestamp, flags); 290} 291