Add proper const declaration to a cast, fixes a warning
[libav.git] / libavformat / avio.c
CommitLineData
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/*@{*/
36static 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}
42static const AVOption options[] = {{NULL}};
43static const AVClass urlcontext_class =
2308b6c1 44 { "URLContext", urlcontext_to_name, options, LIBAVUTIL_VERSION_INT };
5acef35f
BA
45/*@}*/
46#endif
de6d9b64 47
019ac05a
FB
48static int default_interrupt_cb(void);
49
de6d9b64 50URLProtocol *first_protocol = NULL;
019ac05a 51URLInterruptCB *url_interrupt_cb = default_interrupt_cb;
de6d9b64 52
84be6e72
MN
53URLProtocol *av_protocol_next(URLProtocol *p)
54{
55 if(p) return p->next;
56 else return first_protocol;
57}
58
9b07a2dc 59int av_register_protocol2(URLProtocol *protocol, int size)
de6d9b64
FB
60{
61 URLProtocol **p;
9b07a2dc
MS
62 if (size < sizeof(URLProtocol)) {
63 URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
64 memcpy(temp, protocol, size);
65 protocol = temp;
66 }
de6d9b64
FB
67 p = &first_protocol;
68 while (*p != NULL) p = &(*p)->next;
69 *p = protocol;
70 protocol->next = NULL;
71 return 0;
72}
73
65c40e4e 74#if LIBAVFORMAT_VERSION_MAJOR < 53
9b07a2dc
MS
75/* The layout of URLProtocol as of when major was bumped to 52 */
76struct 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
86int av_register_protocol(URLProtocol *protocol)
87{
88 return av_register_protocol2(protocol, sizeof(struct URLProtocol_compat));
89}
90
65c40e4e
SS
91int register_protocol(URLProtocol *protocol)
92{
93 return av_register_protocol(protocol);
94}
95#endif
96
ffbb289a 97static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
02174293 98 const char *filename, int flags)
de6d9b64
FB
99{
100 URLContext *uc;
de6d9b64
FB
101 int err;
102
67d4b3f2
MS
103#if CONFIG_NETWORK
104 if (!ff_network_init())
105 return AVERROR(EIO);
106#endif
31277aeb 107 uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
8a9488b5 108 if (!uc) {
8fa36ae0 109 err = AVERROR(ENOMEM);
8a9488b5
FB
110 goto fail;
111 }
5acef35f
BA
112#if LIBAVFORMAT_VERSION_MAJOR >= 53
113 uc->av_class = &urlcontext_class;
114#endif
62181004 115 uc->filename = (char *) &uc[1];
f746a046 116 strcpy(uc->filename, filename);
de6d9b64
FB
117 uc->prot = up;
118 uc->flags = flags;
119 uc->is_streamed = 0; /* default = not streamed */
8a9488b5 120 uc->max_packet_size = 0; /* default: stream file */
735cf6b2
MS
121 if (up->priv_data_size) {
122 uc->priv_data = av_mallocz(up->priv_data_size);
123 if (up->priv_data_class) {
805488f0 124 *(const AVClass**)uc->priv_data = up->priv_data_class;
735cf6b2
MS
125 av_opt_set_defaults(uc->priv_data);
126 }
127 }
abbae514 128
de6d9b64
FB
129 *puc = uc;
130 return 0;
8a9488b5
FB
131 fail:
132 *puc = NULL;
67d4b3f2
MS
133#if CONFIG_NETWORK
134 ff_network_close();
135#endif
8a9488b5 136 return err;
de6d9b64
FB
137}
138
ffbb289a
MS
139int 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
153int 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
170int url_alloc(URLContext **puc, const char *filename, int flags)
ba99cfc2
RB
171{
172 URLProtocol *up;
173 const char *p;
174 char proto_str[128], *q;
175
176 p = filename;
177 q = proto_str;
178 while (*p != '\0' && *p != ':') {
179 /* protocols can only contain alphabetic chars */
180 if (!isalpha(*p))
181 goto file_proto;
182 if ((q - proto_str) < sizeof(proto_str) - 1)
183 *q++ = *p;
184 p++;
185 }
186 /* if the protocol has length 1, we consider it is a dos drive */
bc574408 187 if (*p == '\0' || is_dos_path(filename)) {
ba99cfc2
RB
188 file_proto:
189 strcpy(proto_str, "file");
190 } else {
191 *q = '\0';
192 }
193
194 up = first_protocol;
195 while (up != NULL) {
196 if (!strcmp(proto_str, up->name))
ffbb289a 197 return url_alloc_for_protocol (puc, up, filename, flags);
ba99cfc2
RB
198 up = up->next;
199 }
200 *puc = NULL;
201 return AVERROR(ENOENT);
202}
203
ffbb289a
MS
204int url_open(URLContext **puc, const char *filename, int flags)
205{
206 int ret = url_alloc(puc, filename, flags);
207 if (ret)
208 return ret;
209 ret = url_connect(*puc);
210 if (!ret)
211 return 0;
212 fail:
213 url_close(*puc);
214 *puc = NULL;
215 return ret;
216}
217
de6d9b64
FB
218int url_read(URLContext *h, unsigned char *buf, int size)
219{
220 int ret;
221 if (h->flags & URL_WRONLY)
6f3e0b21 222 return AVERROR(EIO);
de6d9b64
FB
223 ret = h->prot->url_read(h, buf, size);
224 return ret;
225}
226
0e848977
KS
227int url_read_complete(URLContext *h, unsigned char *buf, int size)
228{
229 int ret, len;
f1d2b572 230 int fast_retries = 5;
0e848977
KS
231
232 len = 0;
233 while (len < size) {
234 ret = url_read(h, buf+len, size-len);
ddb901b7
RD
235 if (ret == AVERROR(EAGAIN)) {
236 ret = 0;
f1d2b572
RD
237 if (fast_retries)
238 fast_retries--;
239 else
240 usleep(1000);
ddb901b7
RD
241 } else if (ret < 1)
242 return ret < 0 ? ret : len;
f1d2b572
RD
243 if (ret)
244 fast_retries = FFMAX(fast_retries, 2);
0e848977
KS
245 len += ret;
246 }
247 return len;
248}
249
27241cbf 250int url_write(URLContext *h, const unsigned char *buf, int size)
de6d9b64
FB
251{
252 int ret;
8a9488b5 253 if (!(h->flags & (URL_WRONLY | URL_RDWR)))
6f3e0b21 254 return AVERROR(EIO);
8a9488b5
FB
255 /* avoid sending too big packets */
256 if (h->max_packet_size && size > h->max_packet_size)
6f3e0b21 257 return AVERROR(EIO);
de6d9b64
FB
258 ret = h->prot->url_write(h, buf, size);
259 return ret;
260}
261
bc5c918e 262int64_t url_seek(URLContext *h, int64_t pos, int whence)
de6d9b64 263{
bc5c918e 264 int64_t ret;
de6d9b64
FB
265
266 if (!h->prot->url_seek)
28894105 267 return AVERROR(ENOSYS);
493f54ad 268 ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
de6d9b64
FB
269 return ret;
270}
271
de6d9b64
FB
272int url_close(URLContext *h)
273{
7a813b36 274 int ret = 0;
346db900 275 if (!h) return 0; /* can happen when url_open fails */
de6d9b64 276
ffbb289a 277 if (h->is_connected && h->prot->url_close)
7a813b36 278 ret = h->prot->url_close(h);
67d4b3f2
MS
279#if CONFIG_NETWORK
280 ff_network_close();
281#endif
735cf6b2
MS
282 if (h->prot->priv_data_size)
283 av_free(h->priv_data);
1ea4f593 284 av_free(h);
de6d9b64
FB
285 return ret;
286}
287
288int url_exist(const char *filename)
289{
290 URLContext *h;
291 if (url_open(&h, filename, URL_RDONLY) < 0)
292 return 0;
293 url_close(h);
294 return 1;
295}
296
bc5c918e 297int64_t url_filesize(URLContext *h)
de6d9b64 298{
bc5c918e 299 int64_t pos, size;
115329f1 300
8e287af0
MN
301 size= url_seek(h, 0, AVSEEK_SIZE);
302 if(size<0){
1ae2c5f2 303 pos = url_seek(h, 0, SEEK_CUR);
eabbae73
RB
304 if ((size = url_seek(h, -1, SEEK_END)) < 0)
305 return size;
306 size++;
1ae2c5f2 307 url_seek(h, pos, SEEK_SET);
8e287af0 308 }
de6d9b64
FB
309 return size;
310}
8a9488b5 311
f0a80394
RB
312int url_get_file_handle(URLContext *h)
313{
314 if (!h->prot->url_get_file_handle)
315 return -1;
316 return h->prot->url_get_file_handle(h);
317}
318
8a9488b5
FB
319int url_get_max_packet_size(URLContext *h)
320{
321 return h->max_packet_size;
322}
f746a046
FB
323
324void url_get_filename(URLContext *h, char *buf, int buf_size)
325{
75e61b0e 326 av_strlcpy(buf, h->filename, buf_size);
f746a046 327}
019ac05a
FB
328
329
330static int default_interrupt_cb(void)
331{
332 return 0;
333}
334
019ac05a
FB
335void url_set_interrupt_cb(URLInterruptCB *interrupt_cb)
336{
337 if (!interrupt_cb)
338 interrupt_cb = default_interrupt_cb;
339 url_interrupt_cb = interrupt_cb;
340}
536333a0 341
502bdf68 342int av_url_read_pause(URLContext *h, int pause)
536333a0
BA
343{
344 if (!h->prot->url_read_pause)
345 return AVERROR(ENOSYS);
502bdf68 346 return h->prot->url_read_pause(h, pause);
536333a0
BA
347}
348
bc5c918e 349int64_t av_url_read_seek(URLContext *h,
536333a0
BA
350 int stream_index, int64_t timestamp, int flags)
351{
352 if (!h->prot->url_read_seek)
353 return AVERROR(ENOSYS);
354 return h->prot->url_read_seek(h, stream_index, timestamp, flags);
355}