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" |
67d4b3f2 MS |
29 | #if CONFIG_NETWORK |
30 | #include "network.h" | |
31 | #endif | |
5acef35f BA |
32 | |
33 | #if LIBAVFORMAT_VERSION_MAJOR >= 53 | |
34 | /** @name Logging context. */ | |
35 | /*@{*/ | |
36 | static 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 | } | |
42 | static const AVOption options[] = {{NULL}}; | |
43 | static const AVClass urlcontext_class = | |
2308b6c1 | 44 | { "URLContext", urlcontext_to_name, options, LIBAVUTIL_VERSION_INT }; |
5acef35f BA |
45 | /*@}*/ |
46 | #endif | |
de6d9b64 | 47 | |
019ac05a FB |
48 | static int default_interrupt_cb(void); |
49 | ||
de6d9b64 | 50 | URLProtocol *first_protocol = NULL; |
019ac05a | 51 | URLInterruptCB *url_interrupt_cb = default_interrupt_cb; |
de6d9b64 | 52 | |
84be6e72 MN |
53 | URLProtocol *av_protocol_next(URLProtocol *p) |
54 | { | |
55 | if(p) return p->next; | |
56 | else return first_protocol; | |
57 | } | |
58 | ||
65c40e4e | 59 | int av_register_protocol(URLProtocol *protocol) |
de6d9b64 FB |
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 | ||
65c40e4e SS |
69 | #if LIBAVFORMAT_VERSION_MAJOR < 53 |
70 | int register_protocol(URLProtocol *protocol) | |
71 | { | |
72 | return av_register_protocol(protocol); | |
73 | } | |
74 | #endif | |
75 | ||
ba99cfc2 RB |
76 | int url_open_protocol (URLContext **puc, struct URLProtocol *up, |
77 | const char *filename, int flags) | |
de6d9b64 FB |
78 | { |
79 | URLContext *uc; | |
de6d9b64 FB |
80 | int err; |
81 | ||
67d4b3f2 MS |
82 | #if CONFIG_NETWORK |
83 | if (!ff_network_init()) | |
84 | return AVERROR(EIO); | |
85 | #endif | |
31277aeb | 86 | uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); |
8a9488b5 | 87 | if (!uc) { |
8fa36ae0 | 88 | err = AVERROR(ENOMEM); |
8a9488b5 FB |
89 | goto fail; |
90 | } | |
5acef35f BA |
91 | #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
92 | uc->av_class = &urlcontext_class; | |
93 | #endif | |
62181004 | 94 | uc->filename = (char *) &uc[1]; |
f746a046 | 95 | strcpy(uc->filename, filename); |
de6d9b64 FB |
96 | uc->prot = up; |
97 | uc->flags = flags; | |
98 | uc->is_streamed = 0; /* default = not streamed */ | |
8a9488b5 | 99 | uc->max_packet_size = 0; /* default: stream file */ |
de6d9b64 FB |
100 | err = up->url_open(uc, filename, flags); |
101 | if (err < 0) { | |
1ea4f593 | 102 | av_free(uc); |
67d4b3f2 | 103 | goto fail; |
de6d9b64 | 104 | } |
abbae514 | 105 | |
48fdb66c | 106 | //We must be careful here as url_seek() could be slow, for example for http |
abbae514 | 107 | if( (flags & (URL_WRONLY | URL_RDWR)) |
ba99cfc2 | 108 | || !strcmp(up->name, "file")) |
abbae514 MN |
109 | if(!uc->is_streamed && url_seek(uc, 0, SEEK_SET) < 0) |
110 | uc->is_streamed= 1; | |
de6d9b64 FB |
111 | *puc = uc; |
112 | return 0; | |
8a9488b5 FB |
113 | fail: |
114 | *puc = NULL; | |
67d4b3f2 MS |
115 | #if CONFIG_NETWORK |
116 | ff_network_close(); | |
117 | #endif | |
8a9488b5 | 118 | return err; |
de6d9b64 FB |
119 | } |
120 | ||
ba99cfc2 RB |
121 | int 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 */ | |
bc574408 | 138 | if (*p == '\0' || is_dos_path(filename)) { |
ba99cfc2 RB |
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 | ||
de6d9b64 FB |
155 | int url_read(URLContext *h, unsigned char *buf, int size) |
156 | { | |
157 | int ret; | |
158 | if (h->flags & URL_WRONLY) | |
6f3e0b21 | 159 | return AVERROR(EIO); |
de6d9b64 FB |
160 | ret = h->prot->url_read(h, buf, size); |
161 | return ret; | |
162 | } | |
163 | ||
0e848977 KS |
164 | int url_read_complete(URLContext *h, unsigned char *buf, int size) |
165 | { | |
166 | int ret, len; | |
f1d2b572 | 167 | int fast_retries = 5; |
0e848977 KS |
168 | |
169 | len = 0; | |
170 | while (len < size) { | |
171 | ret = url_read(h, buf+len, size-len); | |
ddb901b7 RD |
172 | if (ret == AVERROR(EAGAIN)) { |
173 | ret = 0; | |
f1d2b572 RD |
174 | if (fast_retries) |
175 | fast_retries--; | |
176 | else | |
177 | usleep(1000); | |
ddb901b7 RD |
178 | } else if (ret < 1) |
179 | return ret < 0 ? ret : len; | |
f1d2b572 RD |
180 | if (ret) |
181 | fast_retries = FFMAX(fast_retries, 2); | |
0e848977 KS |
182 | len += ret; |
183 | } | |
184 | return len; | |
185 | } | |
186 | ||
de6d9b64 FB |
187 | int url_write(URLContext *h, unsigned char *buf, int size) |
188 | { | |
189 | int ret; | |
8a9488b5 | 190 | if (!(h->flags & (URL_WRONLY | URL_RDWR))) |
6f3e0b21 | 191 | return AVERROR(EIO); |
8a9488b5 FB |
192 | /* avoid sending too big packets */ |
193 | if (h->max_packet_size && size > h->max_packet_size) | |
6f3e0b21 | 194 | return AVERROR(EIO); |
de6d9b64 FB |
195 | ret = h->prot->url_write(h, buf, size); |
196 | return ret; | |
197 | } | |
198 | ||
bc5c918e | 199 | int64_t url_seek(URLContext *h, int64_t pos, int whence) |
de6d9b64 | 200 | { |
bc5c918e | 201 | int64_t ret; |
de6d9b64 FB |
202 | |
203 | if (!h->prot->url_seek) | |
28894105 | 204 | return AVERROR(ENOSYS); |
493f54ad | 205 | ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE); |
de6d9b64 FB |
206 | return ret; |
207 | } | |
208 | ||
de6d9b64 FB |
209 | int url_close(URLContext *h) |
210 | { | |
7a813b36 | 211 | int ret = 0; |
346db900 | 212 | if (!h) return 0; /* can happen when url_open fails */ |
de6d9b64 | 213 | |
7a813b36 AB |
214 | if (h->prot->url_close) |
215 | ret = h->prot->url_close(h); | |
67d4b3f2 MS |
216 | #if CONFIG_NETWORK |
217 | ff_network_close(); | |
218 | #endif | |
1ea4f593 | 219 | av_free(h); |
de6d9b64 FB |
220 | return ret; |
221 | } | |
222 | ||
223 | int 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 | ||
bc5c918e | 232 | int64_t url_filesize(URLContext *h) |
de6d9b64 | 233 | { |
bc5c918e | 234 | int64_t pos, size; |
115329f1 | 235 | |
8e287af0 MN |
236 | size= url_seek(h, 0, AVSEEK_SIZE); |
237 | if(size<0){ | |
1ae2c5f2 | 238 | pos = url_seek(h, 0, SEEK_CUR); |
eabbae73 RB |
239 | if ((size = url_seek(h, -1, SEEK_END)) < 0) |
240 | return size; | |
241 | size++; | |
1ae2c5f2 | 242 | url_seek(h, pos, SEEK_SET); |
8e287af0 | 243 | } |
de6d9b64 FB |
244 | return size; |
245 | } | |
8a9488b5 | 246 | |
f0a80394 RB |
247 | int 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 | ||
8a9488b5 FB |
254 | int url_get_max_packet_size(URLContext *h) |
255 | { | |
256 | return h->max_packet_size; | |
257 | } | |
f746a046 FB |
258 | |
259 | void url_get_filename(URLContext *h, char *buf, int buf_size) | |
260 | { | |
75e61b0e | 261 | av_strlcpy(buf, h->filename, buf_size); |
f746a046 | 262 | } |
019ac05a FB |
263 | |
264 | ||
265 | static int default_interrupt_cb(void) | |
266 | { | |
267 | return 0; | |
268 | } | |
269 | ||
019ac05a FB |
270 | void 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 | } | |
536333a0 | 276 | |
502bdf68 | 277 | int av_url_read_pause(URLContext *h, int pause) |
536333a0 BA |
278 | { |
279 | if (!h->prot->url_read_pause) | |
280 | return AVERROR(ENOSYS); | |
502bdf68 | 281 | return h->prot->url_read_pause(h, pause); |
536333a0 BA |
282 | } |
283 | ||
bc5c918e | 284 | int64_t av_url_read_seek(URLContext *h, |
536333a0 BA |
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 | } |