3 * Copyright (c) 2001 Fabrice Bellard
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/avstring.h"
25 #include "libavutil/opt.h"
26 #include "os_support.h"
33 /** @name Logging context. */
35 static const char *urlcontext_to_name(void *ptr
)
37 URLContext
*h
= (URLContext
*)ptr
;
38 if(h
->prot
) return h
->prot
->name
;
41 static const AVOption options
[] = {{NULL
}};
42 static const AVClass urlcontext_class
= {
43 .class_name
= "URLContext",
44 .item_name
= urlcontext_to_name
,
46 .version
= LIBAVUTIL_VERSION_INT
,
50 static int default_interrupt_cb(void);
52 URLProtocol
*first_protocol
= NULL
;
53 int (*url_interrupt_cb
)(void) = default_interrupt_cb
;
56 URLProtocol
*av_protocol_next(URLProtocol
*p
)
59 else return first_protocol
;
63 const char *avio_enum_protocols(void **opaque
, int output
)
65 URLProtocol
**p
= opaque
;
66 *p
= *p ?
(*p
)->next
: first_protocol
;
68 if ((output
&& (*p
)->url_write
) || (!output
&& (*p
)->url_read
))
70 return avio_enum_protocols(opaque
, output
);
73 int ffurl_register_protocol(URLProtocol
*protocol
, int size
)
76 if (size
< sizeof(URLProtocol
)) {
77 URLProtocol
* temp
= av_mallocz(sizeof(URLProtocol
));
78 memcpy(temp
, protocol
, size
);
82 while (*p
!= NULL
) p
= &(*p
)->next
;
84 protocol
->next
= NULL
;
88 static int url_alloc_for_protocol (URLContext
**puc
, struct URLProtocol
*up
,
89 const char *filename
, int flags
)
95 if (!ff_network_init())
98 uc
= av_mallocz(sizeof(URLContext
) + strlen(filename
) + 1);
100 err
= AVERROR(ENOMEM
);
103 uc
->av_class
= &urlcontext_class
;
104 uc
->filename
= (char *) &uc
[1];
105 strcpy(uc
->filename
, filename
);
108 uc
->is_streamed
= 0; /* default = not streamed */
109 uc
->max_packet_size
= 0; /* default: stream file */
110 if (up
->priv_data_size
) {
111 uc
->priv_data
= av_mallocz(up
->priv_data_size
);
112 if (up
->priv_data_class
) {
113 *(const AVClass
**)uc
->priv_data
= up
->priv_data_class
;
114 av_opt_set_defaults(uc
->priv_data
);
128 int ffurl_connect(URLContext
* uc
)
130 int err
= uc
->prot
->url_open(uc
, uc
->filename
, uc
->flags
);
133 uc
->is_connected
= 1;
134 //We must be careful here as ffurl_seek() could be slow, for example for http
135 if( (uc
->flags
& AVIO_FLAG_WRITE
)
136 || !strcmp(uc
->prot
->name
, "file"))
137 if(!uc
->is_streamed
&& ffurl_seek(uc
, 0, SEEK_SET
) < 0)
143 int url_open_protocol (URLContext
**puc
, struct URLProtocol
*up
,
144 const char *filename
, int flags
)
148 ret
= url_alloc_for_protocol(puc
, up
, filename
, flags
);
151 ret
= ffurl_connect(*puc
);
159 int url_alloc(URLContext
**puc
, const char *filename
, int flags
)
161 return ffurl_alloc(puc
, filename
, flags
);
163 int url_connect(URLContext
* uc
)
165 return ffurl_connect(uc
);
167 int url_open(URLContext
**puc
, const char *filename
, int flags
)
169 return ffurl_open(puc
, filename
, flags
);
171 int url_read(URLContext
*h
, unsigned char *buf
, int size
)
173 return ffurl_read(h
, buf
, size
);
175 int url_read_complete(URLContext
*h
, unsigned char *buf
, int size
)
177 return ffurl_read_complete(h
, buf
, size
);
179 int url_write(URLContext
*h
, const unsigned char *buf
, int size
)
181 return ffurl_write(h
, buf
, size
);
183 int64_t url_seek(URLContext
*h
, int64_t pos
, int whence
)
185 return ffurl_seek(h
, pos
, whence
);
187 int url_close(URLContext
*h
)
189 return ffurl_close(h
);
191 int64_t url_filesize(URLContext
*h
)
193 return ffurl_size(h
);
195 int url_get_file_handle(URLContext
*h
)
197 return ffurl_get_file_handle(h
);
199 int url_get_max_packet_size(URLContext
*h
)
201 return h
->max_packet_size
;
203 void url_get_filename(URLContext
*h
, char *buf
, int buf_size
)
205 av_strlcpy(buf
, h
->filename
, buf_size
);
207 void url_set_interrupt_cb(URLInterruptCB
*interrupt_cb
)
209 avio_set_interrupt_cb(interrupt_cb
);
211 int av_register_protocol2(URLProtocol
*protocol
, int size
)
213 return ffurl_register_protocol(protocol
, size
);
217 #define URL_SCHEME_CHARS \
218 "abcdefghijklmnopqrstuvwxyz" \
219 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
222 int ffurl_alloc(URLContext
**puc
, const char *filename
, int flags
)
225 char proto_str
[128], proto_nested
[128], *ptr
;
226 size_t proto_len
= strspn(filename
, URL_SCHEME_CHARS
);
228 if (filename
[proto_len
] != ':' || is_dos_path(filename
))
229 strcpy(proto_str
, "file");
231 av_strlcpy(proto_str
, filename
, FFMIN(proto_len
+1, sizeof(proto_str
)));
233 av_strlcpy(proto_nested
, proto_str
, sizeof(proto_nested
));
234 if ((ptr
= strchr(proto_nested
, '+')))
239 if (!strcmp(proto_str
, up
->name
))
240 return url_alloc_for_protocol (puc
, up
, filename
, flags
);
241 if (up
->flags
& URL_PROTOCOL_FLAG_NESTED_SCHEME
&&
242 !strcmp(proto_nested
, up
->name
))
243 return url_alloc_for_protocol (puc
, up
, filename
, flags
);
247 return AVERROR(ENOENT
);
250 int ffurl_open(URLContext
**puc
, const char *filename
, int flags
)
252 int ret
= ffurl_alloc(puc
, filename
, flags
);
255 ret
= ffurl_connect(*puc
);
263 static inline int retry_transfer_wrapper(URLContext
*h
, unsigned char *buf
, int size
, int size_min
,
264 int (*transfer_func
)(URLContext
*h
, unsigned char *buf
, int size
))
267 int fast_retries
= 5;
270 while (len
< size_min
) {
271 ret
= transfer_func(h
, buf
+len
, size
-len
);
272 if (ret
== AVERROR(EINTR
))
274 if (h
->flags
& AVIO_FLAG_NONBLOCK
)
276 if (ret
== AVERROR(EAGAIN
)) {
283 return ret
< 0 ? ret
: len
;
285 fast_retries
= FFMAX(fast_retries
, 2);
287 if (url_interrupt_cb())
293 int ffurl_read(URLContext
*h
, unsigned char *buf
, int size
)
295 if (!(h
->flags
& AVIO_FLAG_READ
))
297 return retry_transfer_wrapper(h
, buf
, size
, 1, h
->prot
->url_read
);
300 int ffurl_read_complete(URLContext
*h
, unsigned char *buf
, int size
)
302 if (!(h
->flags
& AVIO_FLAG_READ
))
304 return retry_transfer_wrapper(h
, buf
, size
, size
, h
->prot
->url_read
);
307 int ffurl_write(URLContext
*h
, const unsigned char *buf
, int size
)
309 if (!(h
->flags
& AVIO_FLAG_WRITE
))
311 /* avoid sending too big packets */
312 if (h
->max_packet_size
&& size
> h
->max_packet_size
)
315 return retry_transfer_wrapper(h
, buf
, size
, size
, h
->prot
->url_write
);
318 int64_t ffurl_seek(URLContext
*h
, int64_t pos
, int whence
)
322 if (!h
->prot
->url_seek
)
323 return AVERROR(ENOSYS
);
324 ret
= h
->prot
->url_seek(h
, pos
, whence
& ~AVSEEK_FORCE
);
328 int ffurl_close(URLContext
*h
)
331 if (!h
) return 0; /* can happen when ffurl_open fails */
333 if (h
->is_connected
&& h
->prot
->url_close
)
334 ret
= h
->prot
->url_close(h
);
338 if (h
->prot
->priv_data_size
) {
339 if (h
->prot
->priv_data_class
)
340 av_opt_free(h
->priv_data
);
341 av_free(h
->priv_data
);
348 int url_exist(const char *filename
)
351 if (ffurl_open(&h
, filename
, AVIO_FLAG_READ
) < 0)
358 int avio_check(const char *url
, int flags
)
361 int ret
= ffurl_alloc(&h
, url
, flags
);
365 if (h
->prot
->url_check
) {
366 ret
= h
->prot
->url_check(h
, flags
);
368 ret
= ffurl_connect(h
);
377 int64_t ffurl_size(URLContext
*h
)
381 size
= ffurl_seek(h
, 0, AVSEEK_SIZE
);
383 pos
= ffurl_seek(h
, 0, SEEK_CUR
);
384 if ((size
= ffurl_seek(h
, -1, SEEK_END
)) < 0)
387 ffurl_seek(h
, pos
, SEEK_SET
);
392 int ffurl_get_file_handle(URLContext
*h
)
394 if (!h
->prot
->url_get_file_handle
)
396 return h
->prot
->url_get_file_handle(h
);
399 static int default_interrupt_cb(void)
404 void avio_set_interrupt_cb(int (*interrupt_cb
)(void))
407 interrupt_cb
= default_interrupt_cb
;
408 url_interrupt_cb
= interrupt_cb
;
411 int ff_check_interrupt(AVIOInterruptCB
*cb
)
414 if (cb
&& cb
->callback
&& (ret
= cb
->callback(cb
->opaque
)))
416 return url_interrupt_cb();
420 int av_url_read_pause(URLContext
*h
, int pause
)
422 if (!h
->prot
->url_read_pause
)
423 return AVERROR(ENOSYS
);
424 return h
->prot
->url_read_pause(h
, pause
);
427 int64_t av_url_read_seek(URLContext
*h
,
428 int stream_index
, int64_t timestamp
, int flags
)
430 if (!h
->prot
->url_read_seek
)
431 return AVERROR(ENOSYS
);
432 return h
->prot
->url_read_seek(h
, stream_index
, timestamp
, flags
);