Commit | Line | Data |
---|---|---|
de6d9b64 FB |
1 | /* |
2 | * Unbuffered io for ffmpeg system | |
19720f15 | 3 | * Copyright (c) 2001 Fabrice Bellard |
de6d9b64 | 4 | * |
b78e7197 DB |
5 | * This file is part of FFmpeg. |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
19720f15 FB |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either | |
b78e7197 | 10 | * version 2.1 of the License, or (at your option) any later version. |
de6d9b64 | 11 | * |
b78e7197 | 12 | * FFmpeg is distributed in the hope that it will be useful, |
de6d9b64 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19720f15 FB |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. | |
de6d9b64 | 16 | * |
19720f15 | 17 | * You should have received a copy of the GNU Lesser General Public |
b78e7197 | 18 | * License along with FFmpeg; if not, write to the Free Software |
5509bffa | 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
de6d9b64 | 20 | */ |
245976da | 21 | |
f1d2b572 RD |
22 | /* needed for usleep() */ |
23 | #define _XOPEN_SOURCE 600 | |
24 | #include <unistd.h> | |
245976da DB |
25 | #include "libavutil/avstring.h" |
26 | #include "libavcodec/opt.h" | |
bc574408 | 27 | #include "os_support.h" |
de6d9b64 | 28 | #include "avformat.h" |
5acef35f BA |
29 | |
30 | #if LIBAVFORMAT_VERSION_MAJOR >= 53 | |
31 | /** @name Logging context. */ | |
32 | /*@{*/ | |
33 | static const char *urlcontext_to_name(void *ptr) | |
34 | { | |
35 | URLContext *h = (URLContext *)ptr; | |
36 | if(h->prot) return h->prot->name; | |
37 | else return "NULL"; | |
38 | } | |
39 | static const AVOption options[] = {{NULL}}; | |
40 | static const AVClass urlcontext_class = | |
41 | { "URLContext", urlcontext_to_name, options }; | |
42 | /*@}*/ | |
43 | #endif | |
de6d9b64 | 44 | |
019ac05a FB |
45 | static int default_interrupt_cb(void); |
46 | ||
de6d9b64 | 47 | URLProtocol *first_protocol = NULL; |
019ac05a | 48 | URLInterruptCB *url_interrupt_cb = default_interrupt_cb; |
de6d9b64 | 49 | |
84be6e72 MN |
50 | URLProtocol *av_protocol_next(URLProtocol *p) |
51 | { | |
52 | if(p) return p->next; | |
53 | else return first_protocol; | |
54 | } | |
55 | ||
65c40e4e | 56 | int av_register_protocol(URLProtocol *protocol) |
de6d9b64 FB |
57 | { |
58 | URLProtocol **p; | |
59 | p = &first_protocol; | |
60 | while (*p != NULL) p = &(*p)->next; | |
61 | *p = protocol; | |
62 | protocol->next = NULL; | |
63 | return 0; | |
64 | } | |
65 | ||
65c40e4e SS |
66 | #if LIBAVFORMAT_VERSION_MAJOR < 53 |
67 | int register_protocol(URLProtocol *protocol) | |
68 | { | |
69 | return av_register_protocol(protocol); | |
70 | } | |
71 | #endif | |
72 | ||
ba99cfc2 RB |
73 | int url_open_protocol (URLContext **puc, struct URLProtocol *up, |
74 | const char *filename, int flags) | |
de6d9b64 FB |
75 | { |
76 | URLContext *uc; | |
de6d9b64 FB |
77 | int err; |
78 | ||
31277aeb | 79 | uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); |
8a9488b5 | 80 | if (!uc) { |
8fa36ae0 | 81 | err = AVERROR(ENOMEM); |
8a9488b5 FB |
82 | goto fail; |
83 | } | |
5acef35f BA |
84 | #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
85 | uc->av_class = &urlcontext_class; | |
86 | #endif | |
62181004 | 87 | uc->filename = (char *) &uc[1]; |
f746a046 | 88 | strcpy(uc->filename, filename); |
de6d9b64 FB |
89 | uc->prot = up; |
90 | uc->flags = flags; | |
91 | uc->is_streamed = 0; /* default = not streamed */ | |
8a9488b5 | 92 | uc->max_packet_size = 0; /* default: stream file */ |
de6d9b64 FB |
93 | err = up->url_open(uc, filename, flags); |
94 | if (err < 0) { | |
1ea4f593 | 95 | av_free(uc); |
de6d9b64 FB |
96 | *puc = NULL; |
97 | return err; | |
98 | } | |
abbae514 | 99 | |
48fdb66c | 100 | //We must be careful here as url_seek() could be slow, for example for http |
abbae514 | 101 | if( (flags & (URL_WRONLY | URL_RDWR)) |
ba99cfc2 | 102 | || !strcmp(up->name, "file")) |
abbae514 MN |
103 | if(!uc->is_streamed && url_seek(uc, 0, SEEK_SET) < 0) |
104 | uc->is_streamed= 1; | |
de6d9b64 FB |
105 | *puc = uc; |
106 | return 0; | |
8a9488b5 FB |
107 | fail: |
108 | *puc = NULL; | |
109 | return err; | |
de6d9b64 FB |
110 | } |
111 | ||
ba99cfc2 RB |
112 | int url_open(URLContext **puc, const char *filename, int flags) |
113 | { | |
114 | URLProtocol *up; | |
115 | const char *p; | |
116 | char proto_str[128], *q; | |
117 | ||
118 | p = filename; | |
119 | q = proto_str; | |
120 | while (*p != '\0' && *p != ':') { | |
121 | /* protocols can only contain alphabetic chars */ | |
122 | if (!isalpha(*p)) | |
123 | goto file_proto; | |
124 | if ((q - proto_str) < sizeof(proto_str) - 1) | |
125 | *q++ = *p; | |
126 | p++; | |
127 | } | |
128 | /* if the protocol has length 1, we consider it is a dos drive */ | |
bc574408 | 129 | if (*p == '\0' || is_dos_path(filename)) { |
ba99cfc2 RB |
130 | file_proto: |
131 | strcpy(proto_str, "file"); | |
132 | } else { | |
133 | *q = '\0'; | |
134 | } | |
135 | ||
136 | up = first_protocol; | |
137 | while (up != NULL) { | |
138 | if (!strcmp(proto_str, up->name)) | |
139 | return url_open_protocol (puc, up, filename, flags); | |
140 | up = up->next; | |
141 | } | |
142 | *puc = NULL; | |
143 | return AVERROR(ENOENT); | |
144 | } | |
145 | ||
de6d9b64 FB |
146 | int url_read(URLContext *h, unsigned char *buf, int size) |
147 | { | |
148 | int ret; | |
149 | if (h->flags & URL_WRONLY) | |
6f3e0b21 | 150 | return AVERROR(EIO); |
de6d9b64 FB |
151 | ret = h->prot->url_read(h, buf, size); |
152 | return ret; | |
153 | } | |
154 | ||
0e848977 KS |
155 | int url_read_complete(URLContext *h, unsigned char *buf, int size) |
156 | { | |
157 | int ret, len; | |
f1d2b572 | 158 | int fast_retries = 5; |
0e848977 KS |
159 | |
160 | len = 0; | |
161 | while (len < size) { | |
162 | ret = url_read(h, buf+len, size-len); | |
ddb901b7 RD |
163 | if (ret == AVERROR(EAGAIN)) { |
164 | ret = 0; | |
f1d2b572 RD |
165 | if (fast_retries) |
166 | fast_retries--; | |
167 | else | |
168 | usleep(1000); | |
ddb901b7 RD |
169 | } else if (ret < 1) |
170 | return ret < 0 ? ret : len; | |
f1d2b572 RD |
171 | if (ret) |
172 | fast_retries = FFMAX(fast_retries, 2); | |
0e848977 KS |
173 | len += ret; |
174 | } | |
175 | return len; | |
176 | } | |
177 | ||
de6d9b64 FB |
178 | int url_write(URLContext *h, unsigned char *buf, int size) |
179 | { | |
180 | int ret; | |
8a9488b5 | 181 | if (!(h->flags & (URL_WRONLY | URL_RDWR))) |
6f3e0b21 | 182 | return AVERROR(EIO); |
8a9488b5 FB |
183 | /* avoid sending too big packets */ |
184 | if (h->max_packet_size && size > h->max_packet_size) | |
6f3e0b21 | 185 | return AVERROR(EIO); |
de6d9b64 FB |
186 | ret = h->prot->url_write(h, buf, size); |
187 | return ret; | |
188 | } | |
189 | ||
bc5c918e | 190 | int64_t url_seek(URLContext *h, int64_t pos, int whence) |
de6d9b64 | 191 | { |
bc5c918e | 192 | int64_t ret; |
de6d9b64 FB |
193 | |
194 | if (!h->prot->url_seek) | |
8fa36ae0 | 195 | return AVERROR(EPIPE); |
de6d9b64 FB |
196 | ret = h->prot->url_seek(h, pos, whence); |
197 | return ret; | |
198 | } | |
199 | ||
de6d9b64 FB |
200 | int url_close(URLContext *h) |
201 | { | |
7a813b36 | 202 | int ret = 0; |
346db900 | 203 | if (!h) return 0; /* can happen when url_open fails */ |
de6d9b64 | 204 | |
7a813b36 AB |
205 | if (h->prot->url_close) |
206 | ret = h->prot->url_close(h); | |
1ea4f593 | 207 | av_free(h); |
de6d9b64 FB |
208 | return ret; |
209 | } | |
210 | ||
211 | int url_exist(const char *filename) | |
212 | { | |
213 | URLContext *h; | |
214 | if (url_open(&h, filename, URL_RDONLY) < 0) | |
215 | return 0; | |
216 | url_close(h); | |
217 | return 1; | |
218 | } | |
219 | ||
bc5c918e | 220 | int64_t url_filesize(URLContext *h) |
de6d9b64 | 221 | { |
bc5c918e | 222 | int64_t pos, size; |
115329f1 | 223 | |
8e287af0 MN |
224 | size= url_seek(h, 0, AVSEEK_SIZE); |
225 | if(size<0){ | |
1ae2c5f2 | 226 | pos = url_seek(h, 0, SEEK_CUR); |
eabbae73 RB |
227 | if ((size = url_seek(h, -1, SEEK_END)) < 0) |
228 | return size; | |
229 | size++; | |
1ae2c5f2 | 230 | url_seek(h, pos, SEEK_SET); |
8e287af0 | 231 | } |
de6d9b64 FB |
232 | return size; |
233 | } | |
8a9488b5 | 234 | |
f0a80394 RB |
235 | int url_get_file_handle(URLContext *h) |
236 | { | |
237 | if (!h->prot->url_get_file_handle) | |
238 | return -1; | |
239 | return h->prot->url_get_file_handle(h); | |
240 | } | |
241 | ||
8a9488b5 FB |
242 | int url_get_max_packet_size(URLContext *h) |
243 | { | |
244 | return h->max_packet_size; | |
245 | } | |
f746a046 FB |
246 | |
247 | void url_get_filename(URLContext *h, char *buf, int buf_size) | |
248 | { | |
75e61b0e | 249 | av_strlcpy(buf, h->filename, buf_size); |
f746a046 | 250 | } |
019ac05a FB |
251 | |
252 | ||
253 | static int default_interrupt_cb(void) | |
254 | { | |
255 | return 0; | |
256 | } | |
257 | ||
019ac05a FB |
258 | void url_set_interrupt_cb(URLInterruptCB *interrupt_cb) |
259 | { | |
260 | if (!interrupt_cb) | |
261 | interrupt_cb = default_interrupt_cb; | |
262 | url_interrupt_cb = interrupt_cb; | |
263 | } | |
536333a0 | 264 | |
502bdf68 | 265 | int av_url_read_pause(URLContext *h, int pause) |
536333a0 BA |
266 | { |
267 | if (!h->prot->url_read_pause) | |
268 | return AVERROR(ENOSYS); | |
502bdf68 | 269 | return h->prot->url_read_pause(h, pause); |
536333a0 BA |
270 | } |
271 | ||
bc5c918e | 272 | int64_t av_url_read_seek(URLContext *h, |
536333a0 BA |
273 | int stream_index, int64_t timestamp, int flags) |
274 | { | |
275 | if (!h->prot->url_read_seek) | |
276 | return AVERROR(ENOSYS); | |
277 | return h->prot->url_read_seek(h, stream_index, timestamp, flags); | |
278 | } |