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