ffmpeg / libavformat / avio.c @ 3ce3b498
History | View | Annotate | Download (9.13 KB)
1 | de6d9b64 | Fabrice Bellard | /*
|
---|---|---|---|
2 | * Unbuffered io for ffmpeg system
|
||
3 | 19720f15 | Fabrice Bellard | * Copyright (c) 2001 Fabrice Bellard
|
4 | de6d9b64 | Fabrice Bellard | *
|
5 | b78e7197 | Diego Biurrun | * This file is part of FFmpeg.
|
6 | *
|
||
7 | * FFmpeg is free software; you can redistribute it and/or
|
||
8 | 19720f15 | Fabrice Bellard | * modify it under the terms of the GNU Lesser General Public
|
9 | * License as published by the Free Software Foundation; either
|
||
10 | b78e7197 | Diego Biurrun | * version 2.1 of the License, or (at your option) any later version.
|
11 | de6d9b64 | Fabrice Bellard | *
|
12 | b78e7197 | Diego Biurrun | * FFmpeg is distributed in the hope that it will be useful,
|
13 | de6d9b64 | Fabrice Bellard | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | 19720f15 | Fabrice Bellard | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 | * Lesser General Public License for more details.
|
||
16 | de6d9b64 | Fabrice Bellard | *
|
17 | 19720f15 | Fabrice Bellard | * You should have received a copy of the GNU Lesser General Public
|
18 | b78e7197 | Diego Biurrun | * License along with FFmpeg; if not, write to the Free Software
|
19 | 5509bffa | Diego Biurrun | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
20 | de6d9b64 | Fabrice Bellard | */
|
21 | 245976da | Diego Biurrun | |
22 | f1d2b572 | Reimar Döffinger | /* needed for usleep() */
|
23 | #define _XOPEN_SOURCE 600 |
||
24 | #include <unistd.h> |
||
25 | 245976da | Diego Biurrun | #include "libavutil/avstring.h" |
26 | 6ed04040 | Michael Niedermayer | #include "libavutil/opt.h" |
27 | bc574408 | Ramiro Polla | #include "os_support.h" |
28 | de6d9b64 | Fabrice Bellard | #include "avformat.h" |
29 | 67d4b3f2 | Martin Storsjö | #if CONFIG_NETWORK
|
30 | #include "network.h" |
||
31 | #endif
|
||
32 | 5acef35f | Björn Axelsson | |
33 | 404eba44 | Aurelien Jacobs | #if FF_API_URL_CLASS
|
34 | 5acef35f | Björn Axelsson | /** @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 = |
||
44 | 2308b6c1 | Michael Niedermayer | { "URLContext", urlcontext_to_name, options, LIBAVUTIL_VERSION_INT };
|
45 | 5acef35f | Björn Axelsson | /*@}*/
|
46 | #endif
|
||
47 | de6d9b64 | Fabrice Bellard | |
48 | 019ac05a | Fabrice Bellard | static int default_interrupt_cb(void); |
49 | |||
50 | de6d9b64 | Fabrice Bellard | URLProtocol *first_protocol = NULL;
|
51 | 019ac05a | Fabrice Bellard | URLInterruptCB *url_interrupt_cb = default_interrupt_cb; |
52 | de6d9b64 | Fabrice Bellard | |
53 | 84be6e72 | Michael Niedermayer | URLProtocol *av_protocol_next(URLProtocol *p) |
54 | { |
||
55 | if(p) return p->next; |
||
56 | else return first_protocol; |
||
57 | } |
||
58 | |||
59 | 9b07a2dc | Martin Storsjö | int av_register_protocol2(URLProtocol *protocol, int size) |
60 | de6d9b64 | Fabrice Bellard | { |
61 | URLProtocol **p; |
||
62 | 9b07a2dc | Martin Storsjö | if (size < sizeof(URLProtocol)) { |
63 | URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
|
||
64 | memcpy(temp, protocol, size); |
||
65 | protocol = temp; |
||
66 | } |
||
67 | de6d9b64 | Fabrice Bellard | p = &first_protocol; |
68 | while (*p != NULL) p = &(*p)->next; |
||
69 | *p = protocol; |
||
70 | protocol->next = NULL;
|
||
71 | return 0; |
||
72 | } |
||
73 | |||
74 | 838b27b4 | Aurelien Jacobs | #if FF_API_REGISTER_PROTOCOL
|
75 | 9b07a2dc | Martin Storsjö | /* The layout of URLProtocol as of when major was bumped to 52 */
|
76 | struct URLProtocol_compat {
|
||
77 | const char *name; |
||
78 | int (*url_open)(URLContext *h, const char *filename, int flags); |
||
79 | int (*url_read)(URLContext *h, unsigned char *buf, int size); |
||
80 | int (*url_write)(URLContext *h, unsigned char *buf, int size); |
||
81 | int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);
|
||
82 | int (*url_close)(URLContext *h);
|
||
83 | struct URLProtocol *next;
|
||
84 | }; |
||
85 | |||
86 | int av_register_protocol(URLProtocol *protocol)
|
||
87 | { |
||
88 | return av_register_protocol2(protocol, sizeof(struct URLProtocol_compat)); |
||
89 | } |
||
90 | |||
91 | 65c40e4e | Stefano Sabatini | int register_protocol(URLProtocol *protocol)
|
92 | { |
||
93 | 0a216bd1 | Stefano Sabatini | return av_register_protocol2(protocol, sizeof(struct URLProtocol_compat)); |
94 | 65c40e4e | Stefano Sabatini | } |
95 | #endif
|
||
96 | |||
97 | ffbb289a | Martin Storsjö | static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, |
98 | 02174293 | Martin Storsjö | const char *filename, int flags) |
99 | de6d9b64 | Fabrice Bellard | { |
100 | URLContext *uc; |
||
101 | int err;
|
||
102 | |||
103 | 67d4b3f2 | Martin Storsjö | #if CONFIG_NETWORK
|
104 | if (!ff_network_init())
|
||
105 | return AVERROR(EIO);
|
||
106 | #endif
|
||
107 | 31277aeb | Daniel Kristjansson | uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); |
108 | 8a9488b5 | Fabrice Bellard | if (!uc) {
|
109 | 8fa36ae0 | François Revol | err = AVERROR(ENOMEM); |
110 | 8a9488b5 | Fabrice Bellard | goto fail;
|
111 | } |
||
112 | 404eba44 | Aurelien Jacobs | #if FF_API_URL_CLASS
|
113 | 5acef35f | Björn Axelsson | uc->av_class = &urlcontext_class; |
114 | #endif
|
||
115 | 62181004 | Ronald S. Bultje | uc->filename = (char *) &uc[1]; |
116 | f746a046 | Fabrice Bellard | strcpy(uc->filename, filename); |
117 | de6d9b64 | Fabrice Bellard | uc->prot = up; |
118 | uc->flags = flags; |
||
119 | uc->is_streamed = 0; /* default = not streamed */ |
||
120 | 8a9488b5 | Fabrice Bellard | uc->max_packet_size = 0; /* default: stream file */ |
121 | 735cf6b2 | Martin Storsjö | if (up->priv_data_size) {
|
122 | uc->priv_data = av_mallocz(up->priv_data_size); |
||
123 | if (up->priv_data_class) {
|
||
124 | 805488f0 | Eli Friedman | *(const AVClass**)uc->priv_data = up->priv_data_class;
|
125 | 735cf6b2 | Martin Storsjö | av_opt_set_defaults(uc->priv_data); |
126 | } |
||
127 | } |
||
128 | abbae514 | Michael Niedermayer | |
129 | de6d9b64 | Fabrice Bellard | *puc = uc; |
130 | return 0; |
||
131 | 8a9488b5 | Fabrice Bellard | fail:
|
132 | *puc = NULL;
|
||
133 | 67d4b3f2 | Martin Storsjö | #if CONFIG_NETWORK
|
134 | ff_network_close(); |
||
135 | #endif
|
||
136 | 8a9488b5 | Fabrice Bellard | return err;
|
137 | de6d9b64 | Fabrice Bellard | } |
138 | |||
139 | ffbb289a | Martin Storsjö | int url_connect(URLContext* uc)
|
140 | { |
||
141 | int err = uc->prot->url_open(uc, uc->filename, uc->flags);
|
||
142 | if (err)
|
||
143 | return err;
|
||
144 | uc->is_connected = 1;
|
||
145 | //We must be careful here as url_seek() could be slow, for example for http
|
||
146 | if( (uc->flags & (URL_WRONLY | URL_RDWR))
|
||
147 | || !strcmp(uc->prot->name, "file"))
|
||
148 | if(!uc->is_streamed && url_seek(uc, 0, SEEK_SET) < 0) |
||
149 | uc->is_streamed= 1;
|
||
150 | return 0; |
||
151 | } |
||
152 | |||
153 | int url_open_protocol (URLContext **puc, struct URLProtocol *up, |
||
154 | const char *filename, int flags) |
||
155 | { |
||
156 | int ret;
|
||
157 | |||
158 | ret = url_alloc_for_protocol(puc, up, filename, flags); |
||
159 | if (ret)
|
||
160 | goto fail;
|
||
161 | ret = url_connect(*puc); |
||
162 | if (!ret)
|
||
163 | return 0; |
||
164 | fail:
|
||
165 | url_close(*puc); |
||
166 | *puc = NULL;
|
||
167 | return ret;
|
||
168 | } |
||
169 | |||
170 | 2bab5d3e | Måns Rullgård | #define URL_SCHEME_CHARS \
|
171 | "abcdefghijklmnopqrstuvwxyz" \
|
||
172 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
||
173 | "0123456789+-."
|
||
174 | |||
175 | ffbb289a | Martin Storsjö | int url_alloc(URLContext **puc, const char *filename, int flags) |
176 | ba99cfc2 | Ronald S. Bultje | { |
177 | URLProtocol *up; |
||
178 | 2bab5d3e | Måns Rullgård | char proto_str[128]; |
179 | size_t proto_len = strspn(filename, URL_SCHEME_CHARS); |
||
180 | |||
181 | if (filename[proto_len] != ':' || is_dos_path(filename)) |
||
182 | ba99cfc2 | Ronald S. Bultje | strcpy(proto_str, "file");
|
183 | 2bab5d3e | Måns Rullgård | else
|
184 | av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str))); |
||
185 | ba99cfc2 | Ronald S. Bultje | |
186 | up = first_protocol; |
||
187 | while (up != NULL) { |
||
188 | if (!strcmp(proto_str, up->name))
|
||
189 | ffbb289a | Martin Storsjö | return url_alloc_for_protocol (puc, up, filename, flags);
|
190 | ba99cfc2 | Ronald S. Bultje | up = up->next; |
191 | } |
||
192 | *puc = NULL;
|
||
193 | return AVERROR(ENOENT);
|
||
194 | } |
||
195 | |||
196 | ffbb289a | Martin Storsjö | int url_open(URLContext **puc, const char *filename, int flags) |
197 | { |
||
198 | int ret = url_alloc(puc, filename, flags);
|
||
199 | if (ret)
|
||
200 | return ret;
|
||
201 | ret = url_connect(*puc); |
||
202 | if (!ret)
|
||
203 | return 0; |
||
204 | url_close(*puc); |
||
205 | *puc = NULL;
|
||
206 | return ret;
|
||
207 | } |
||
208 | |||
209 | 3ce3b498 | Nicolas George | static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min, |
210 | a46f7516 | Michael Niedermayer | int (*transfer_func)(URLContext *h, unsigned char *buf, int size)) |
211 | 0e848977 | Kostya Shishkov | { |
212 | int ret, len;
|
||
213 | f1d2b572 | Reimar Döffinger | int fast_retries = 5; |
214 | 0e848977 | Kostya Shishkov | |
215 | len = 0;
|
||
216 | 3ce3b498 | Nicolas George | while (len < size_min) {
|
217 | if (url_interrupt_cb())
|
||
218 | return AVERROR(EINTR);
|
||
219 | a46f7516 | Michael Niedermayer | ret = transfer_func(h, buf+len, size-len); |
220 | 3ce3b498 | Nicolas George | if (ret == AVERROR(EINTR))
|
221 | continue;
|
||
222 | if (h->flags & URL_FLAG_NONBLOCK)
|
||
223 | return ret;
|
||
224 | ddb901b7 | Reimar Döffinger | if (ret == AVERROR(EAGAIN)) {
|
225 | ret = 0;
|
||
226 | f1d2b572 | Reimar Döffinger | if (fast_retries)
|
227 | fast_retries--; |
||
228 | else
|
||
229 | usleep(1000);
|
||
230 | ddb901b7 | Reimar Döffinger | } else if (ret < 1) |
231 | return ret < 0 ? ret : len; |
||
232 | f1d2b572 | Reimar Döffinger | if (ret)
|
233 | fast_retries = FFMAX(fast_retries, 2);
|
||
234 | 0e848977 | Kostya Shishkov | len += ret; |
235 | } |
||
236 | return len;
|
||
237 | } |
||
238 | |||
239 | 3ce3b498 | Nicolas George | int url_read(URLContext *h, unsigned char *buf, int size) |
240 | { |
||
241 | if (h->flags & URL_WRONLY)
|
||
242 | return AVERROR(EIO);
|
||
243 | return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read); |
||
244 | } |
||
245 | |||
246 | a46f7516 | Michael Niedermayer | int url_read_complete(URLContext *h, unsigned char *buf, int size) |
247 | { |
||
248 | 3ce3b498 | Nicolas George | if (h->flags & URL_WRONLY)
|
249 | return AVERROR(EIO);
|
||
250 | return retry_transfer_wrapper(h, buf, size, size, h->prot->url_read);
|
||
251 | a46f7516 | Michael Niedermayer | } |
252 | |||
253 | 27241cbf | Martin Storsjö | int url_write(URLContext *h, const unsigned char *buf, int size) |
254 | de6d9b64 | Fabrice Bellard | { |
255 | 8a9488b5 | Fabrice Bellard | if (!(h->flags & (URL_WRONLY | URL_RDWR)))
|
256 | 6f3e0b21 | Panagiotis Issaris | return AVERROR(EIO);
|
257 | 8a9488b5 | Fabrice Bellard | /* avoid sending too big packets */
|
258 | if (h->max_packet_size && size > h->max_packet_size)
|
||
259 | 6f3e0b21 | Panagiotis Issaris | return AVERROR(EIO);
|
260 | fe5feaeb | Michael Niedermayer | |
261 | 3ce3b498 | Nicolas George | return retry_transfer_wrapper(h, buf, size, size, h->prot->url_write);
|
262 | de6d9b64 | Fabrice Bellard | } |
263 | |||
264 | bc5c918e | Diego Biurrun | int64_t url_seek(URLContext *h, int64_t pos, int whence)
|
265 | de6d9b64 | Fabrice Bellard | { |
266 | bc5c918e | Diego Biurrun | int64_t ret; |
267 | de6d9b64 | Fabrice Bellard | |
268 | if (!h->prot->url_seek)
|
||
269 | 28894105 | Stefano Sabatini | return AVERROR(ENOSYS);
|
270 | 493f54ad | Michael Niedermayer | ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE); |
271 | de6d9b64 | Fabrice Bellard | return ret;
|
272 | } |
||
273 | |||
274 | int url_close(URLContext *h)
|
||
275 | { |
||
276 | 7a813b36 | Alex Beregszaszi | int ret = 0; |
277 | 346db900 | Thorsten Jordan | if (!h) return 0; /* can happen when url_open fails */ |
278 | de6d9b64 | Fabrice Bellard | |
279 | ffbb289a | Martin Storsjö | if (h->is_connected && h->prot->url_close)
|
280 | 7a813b36 | Alex Beregszaszi | ret = h->prot->url_close(h); |
281 | 67d4b3f2 | Martin Storsjö | #if CONFIG_NETWORK
|
282 | ff_network_close(); |
||
283 | #endif
|
||
284 | 735cf6b2 | Martin Storsjö | if (h->prot->priv_data_size)
|
285 | av_free(h->priv_data); |
||
286 | 1ea4f593 | Fabrice Bellard | av_free(h); |
287 | de6d9b64 | Fabrice Bellard | return ret;
|
288 | } |
||
289 | |||
290 | int url_exist(const char *filename) |
||
291 | { |
||
292 | URLContext *h; |
||
293 | if (url_open(&h, filename, URL_RDONLY) < 0) |
||
294 | return 0; |
||
295 | url_close(h); |
||
296 | return 1; |
||
297 | } |
||
298 | |||
299 | bc5c918e | Diego Biurrun | int64_t url_filesize(URLContext *h) |
300 | de6d9b64 | Fabrice Bellard | { |
301 | bc5c918e | Diego Biurrun | int64_t pos, size; |
302 | 115329f1 | Diego Biurrun | |
303 | 8e287af0 | Michael Niedermayer | size= url_seek(h, 0, AVSEEK_SIZE);
|
304 | if(size<0){ |
||
305 | 1ae2c5f2 | Michael Niedermayer | pos = url_seek(h, 0, SEEK_CUR);
|
306 | eabbae73 | Ronald S. Bultje | if ((size = url_seek(h, -1, SEEK_END)) < 0) |
307 | return size;
|
||
308 | size++; |
||
309 | 1ae2c5f2 | Michael Niedermayer | url_seek(h, pos, SEEK_SET); |
310 | 8e287af0 | Michael Niedermayer | } |
311 | de6d9b64 | Fabrice Bellard | return size;
|
312 | } |
||
313 | 8a9488b5 | Fabrice Bellard | |
314 | f0a80394 | Ronald S. Bultje | int url_get_file_handle(URLContext *h)
|
315 | { |
||
316 | if (!h->prot->url_get_file_handle)
|
||
317 | return -1; |
||
318 | return h->prot->url_get_file_handle(h);
|
||
319 | } |
||
320 | |||
321 | 8a9488b5 | Fabrice Bellard | int url_get_max_packet_size(URLContext *h)
|
322 | { |
||
323 | return h->max_packet_size;
|
||
324 | } |
||
325 | f746a046 | Fabrice Bellard | |
326 | void url_get_filename(URLContext *h, char *buf, int buf_size) |
||
327 | { |
||
328 | 75e61b0e | Måns Rullgård | av_strlcpy(buf, h->filename, buf_size); |
329 | f746a046 | Fabrice Bellard | } |
330 | 019ac05a | Fabrice Bellard | |
331 | |||
332 | static int default_interrupt_cb(void) |
||
333 | { |
||
334 | return 0; |
||
335 | } |
||
336 | |||
337 | void url_set_interrupt_cb(URLInterruptCB *interrupt_cb)
|
||
338 | { |
||
339 | if (!interrupt_cb)
|
||
340 | interrupt_cb = default_interrupt_cb; |
||
341 | url_interrupt_cb = interrupt_cb; |
||
342 | } |
||
343 | 536333a0 | Björn Axelsson | |
344 | 502bdf68 | Michael Niedermayer | int av_url_read_pause(URLContext *h, int pause) |
345 | 536333a0 | Björn Axelsson | { |
346 | if (!h->prot->url_read_pause)
|
||
347 | return AVERROR(ENOSYS);
|
||
348 | 502bdf68 | Michael Niedermayer | return h->prot->url_read_pause(h, pause);
|
349 | 536333a0 | Björn Axelsson | } |
350 | |||
351 | bc5c918e | Diego Biurrun | int64_t av_url_read_seek(URLContext *h, |
352 | 536333a0 | Björn Axelsson | int stream_index, int64_t timestamp, int flags) |
353 | { |
||
354 | if (!h->prot->url_read_seek)
|
||
355 | return AVERROR(ENOSYS);
|
||
356 | return h->prot->url_read_seek(h, stream_index, timestamp, flags);
|
||
357 | } |