]> git.sesse.net Git - vlc/blob - modules/access/avio.c
Revert "Remove version sort option. Now uses version sort by default and there's...
[vlc] / modules / access / avio.c
1 /*****************************************************************************
2  * avio.c: access using libavformat library
3  *****************************************************************************
4  * Copyright (C) 2009 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <assert.h>
28
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_access.h>
32 #include <vlc_sout.h>
33 #include <vlc_avcodec.h>
34
35 #include "avio.h"
36
37 #if LIBAVFORMAT_VERSION_MAJOR < 54
38 # define AVIOContext URLContext
39
40 # define avio_open url_open
41 # define avio_close url_close
42 # define avio_read url_read
43 # define avio_seek url_seek
44 # define avio_pause av_url_read_pause
45
46 # define AVIO_FLAG_READ URL_RDONLY
47 # define AVIO_FLAG_WRITE URL_WRONLY
48 # define avio_size url_filesize
49 #endif
50
51 /*****************************************************************************
52  * Module descriptor
53  *****************************************************************************/
54 #ifndef MERGE_FFMPEG
55 vlc_module_begin()
56     AVIO_MODULE
57 vlc_module_end()
58 #endif
59
60 /*****************************************************************************
61  * Local prototypes
62  *****************************************************************************/
63 static ssize_t Read   (access_t *, uint8_t *, size_t);
64 static int     Seek   (access_t *, uint64_t);
65 static int     Control(access_t *, int, va_list);
66 static ssize_t Write(sout_access_out_t *, block_t *);
67 static int     OutControl(sout_access_out_t *, int, va_list);
68 static int     OutSeek (sout_access_out_t *, off_t);
69
70 static int UrlInterruptCallback(void *access)
71 {
72     return !vlc_object_alive((vlc_object_t*)access);
73 }
74
75 struct access_sys_t {
76     AVIOContext *context;
77 };
78
79 struct sout_access_out_sys_t {
80     AVIOContext *context;
81 };
82
83
84 /* */
85
86 #if LIBAVFORMAT_VERSION_MAJOR < 54
87 static vlc_object_t *current_access = NULL;
88
89 static int UrlInterruptCallbackSingle(void)
90 {
91     return UrlInterruptCallback(current_access);
92 }
93
94 static int SetupAvioCb(vlc_object_t *access)
95 {
96     static vlc_mutex_t avio_lock = VLC_STATIC_MUTEX;
97     vlc_mutex_lock(&avio_lock);
98     assert(!access != !current_access);
99     if (access && current_access) {
100         vlc_mutex_unlock(&avio_lock);
101         return VLC_EGENERIC;
102     }
103     url_set_interrupt_cb(access ? UrlInterruptCallbackSingle : NULL);
104
105     current_access = access;
106
107     vlc_mutex_unlock(&avio_lock);
108
109     return VLC_SUCCESS;
110 }
111 #endif
112
113 /* */
114
115 int OpenAvio(vlc_object_t *object)
116 {
117     access_t *access = (access_t*)object;
118     access_sys_t *sys = malloc(sizeof(*sys));
119     if (!sys)
120         return VLC_ENOMEM;
121     sys->context = NULL;
122
123     /* We accept:
124      * - avio://full_url
125      * - url (only a subset of available protocols).
126      */
127     char *url;
128     if (!strcmp(access->psz_access, "avio"))
129         url = strdup(access->psz_location);
130     else if (asprintf(&url, "%s://%s", access->psz_access,
131                       access->psz_location) < 0)
132         url = NULL;
133
134     if (!url) {
135         free(sys);
136         return VLC_ENOMEM;
137     }
138
139     /* */
140     vlc_avcodec_lock();
141     av_register_all();
142     vlc_avcodec_unlock();
143
144     int ret;
145 #if LIBAVFORMAT_VERSION_MAJOR < 54
146     ret = avio_open(&sys->context, url, AVIO_FLAG_READ);
147 #else
148     AVIOInterruptCB cb = {
149         .callback = UrlInterruptCallback,
150         .opaque = access,
151     };
152     ret = avio_open2(&sys->context, url, AVIO_FLAG_READ, &cb, NULL /* options */);
153 #endif
154     if (ret < 0) {
155         errno = AVUNERROR(ret);
156         msg_Err(access, "Failed to open %s: %m", url);
157         free(url);
158         goto error;
159     }
160     free(url);
161
162 #if LIBAVFORMAT_VERSION_MAJOR < 54
163     /* We can accept only one active user at any time */
164     if (SetupAvioCb(VLC_OBJECT(access))) {
165         msg_Err(access, "Module aready in use");
166         avio_close(sys->context);
167         goto error;
168     }
169 #endif
170
171     int64_t size = avio_size(sys->context);
172     bool seekable;
173 #if LIBAVFORMAT_VERSION_MAJOR < 54
174     seekable = !sys->context->is_streamed;
175 #else
176     seekable = sys->context->seekable;
177 #endif
178     msg_Dbg(access, "%sseekable, size=%"PRIi64, seekable ? "" : "not ", size);
179
180     /* */
181     access_InitFields(access);
182     access->info.i_size = size > 0 ? size : 0;
183
184     access->pf_read = Read;
185     access->pf_block = NULL;
186     access->pf_control = Control;
187     access->pf_seek = Seek;
188     access->p_sys = sys;
189
190     return VLC_SUCCESS;
191
192 error:
193     free(sys);
194     return VLC_EGENERIC;
195 }
196
197 /* */
198 int OutOpenAvio(vlc_object_t *object)
199 {
200     sout_access_out_t *access = (sout_access_out_t*)object;
201     sout_access_out_sys_t *sys = malloc(sizeof(*sys));
202     if (!sys)
203         return VLC_ENOMEM;
204     sys->context = NULL;
205
206     /* */
207     vlc_avcodec_lock();
208     av_register_all();
209     vlc_avcodec_unlock();
210
211     if (!access->psz_path)
212         goto error;
213
214     int ret;
215 #if LIBAVFORMAT_VERSION_MAJOR < 54
216     ret = avio_open(&sys->context, access->psz_path, AVIO_FLAG_WRITE);
217 #else
218     AVIOInterruptCB cb = {
219         .callback = UrlInterruptCallback,
220         .opaque = access,
221     };
222     ret = avio_open2(&sys->context, access->psz_path, AVIO_FLAG_WRITE,
223                      &cb, NULL /* options */);
224 #endif
225     if (ret < 0) {
226         errno = AVUNERROR(ret);
227         msg_Err(access, "Failed to open %s", access->psz_path);
228         goto error;
229     }
230
231 #if LIBAVFORMAT_VERSION_MAJOR < 54
232     /* We can accept only one active user at any time */
233     if (SetupAvioCb(VLC_OBJECT(access))) {
234         msg_Err(access, "Module aready in use");
235         goto error;
236     }
237 #endif
238
239     access->pf_write = Write;
240     access->pf_control = OutControl;
241     access->pf_seek = OutSeek;
242     access->p_sys = sys;
243
244     return VLC_SUCCESS;
245
246 error:
247     free(sys);
248     return VLC_EGENERIC;
249 }
250
251 void CloseAvio(vlc_object_t *object)
252 {
253     access_t *access = (access_t*)object;
254     access_sys_t *sys = access->p_sys;
255
256 #if LIBAVFORMAT_VERSION_MAJOR < 54
257     SetupAvioCb(NULL);
258 #endif
259
260     avio_close(sys->context);
261     free(sys);
262 }
263
264 void OutCloseAvio(vlc_object_t *object)
265 {
266     sout_access_out_t *access = (sout_access_out_t*)object;
267     sout_access_out_sys_t *sys = access->p_sys;
268
269 #if LIBAVFORMAT_VERSION_MAJOR < 54
270     SetupAvioCb(NULL);
271 #endif
272
273     avio_close(sys->context);
274     free(sys);
275 }
276
277 static ssize_t Read(access_t *access, uint8_t *data, size_t size)
278 {
279     int r = avio_read(access->p_sys->context, data, size);
280     if (r > 0)
281         access->info.i_pos += r;
282     else
283         access->info.b_eof = true;
284     return r;
285 }
286
287 /*****************************************************************************
288  * Write:
289  *****************************************************************************/
290 static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer)
291 {
292     access_sys_t *p_sys = (access_sys_t*)p_access->p_sys;
293     size_t i_write = 0;
294
295     while (p_buffer != NULL) {
296         block_t *p_next = p_buffer->p_next;
297
298 #if LIBAVFORMAT_VERSION_MAJOR < 54
299         int written = url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
300         if (written < 0) {
301             errno = AVUNERROR(written);
302             goto error;
303         }
304         i_write += written;
305 #else
306         avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
307         avio_flush(p_sys->context);
308         if (p_sys->context->error) {
309             errno = AVUNERROR(p_sys->context->error);
310             p_sys->context->error = 0; /* FIXME? */
311             goto error;
312         }
313         i_write += p_buffer->i_buffer;
314 #endif
315
316         block_Release(p_buffer);
317
318         p_buffer = p_next;
319     }
320
321     return i_write;
322
323 error:
324     msg_Err(p_access, "Wrote only %zu bytes (%m)", i_write);
325     block_ChainRelease( p_buffer );
326     return i_write;
327 }
328
329 static int Seek(access_t *access, uint64_t position)
330 {
331     access_sys_t *sys = access->p_sys;
332     int ret;
333
334 #ifndef EOVERFLOW
335 # define EOVERFLOW EFBIG
336 #endif
337
338     if (position > INT64_MAX)
339         ret = AVERROR(EOVERFLOW);
340     else
341         ret = avio_seek(sys->context, position, SEEK_SET);
342     if (ret < 0) {
343         errno = AVUNERROR(ret);
344         msg_Err(access, "Seek to %"PRIu64" failed: %m", position);
345         if (access->info.i_size <= 0 || position != access->info.i_size)
346             return VLC_EGENERIC;
347     }
348     access->info.i_pos = position;
349     access->info.b_eof = false;
350     return VLC_SUCCESS;
351 }
352
353 static int OutSeek(sout_access_out_t *p_access, off_t i_pos)
354 {
355     sout_access_out_sys_t *sys = p_access->p_sys;
356
357     if (avio_seek(sys->context, i_pos, SEEK_SET) < 0)
358         return VLC_EGENERIC;
359     return VLC_SUCCESS;
360 }
361
362 static int OutControl(sout_access_out_t *p_access, int i_query, va_list args)
363 {
364     sout_access_out_sys_t *p_sys = p_access->p_sys;
365
366     VLC_UNUSED(p_sys);
367     switch (i_query) {
368     case ACCESS_OUT_CONTROLS_PACE: {
369         bool *pb = va_arg(args, bool *);
370         //*pb = strcmp(p_access->psz_access, "stream");
371         *pb = false;
372         break;
373     }
374
375     default:
376         return VLC_EGENERIC;
377     }
378     return VLC_SUCCESS;
379 }
380
381 static int Control(access_t *access, int query, va_list args)
382 {
383     access_sys_t *sys = access->p_sys;
384     bool *b;
385
386     switch (query) {
387     case ACCESS_CAN_SEEK:
388     case ACCESS_CAN_FASTSEEK: /* FIXME how to do that ? */
389         b = va_arg(args, bool *);
390 #if LIBAVFORMAT_VERSION_MAJOR < 54
391         *b = !sys->context->is_streamed;
392 #else
393         *b = sys->context->seekable;
394 #endif
395         return VLC_SUCCESS;
396     case ACCESS_CAN_PAUSE:
397         b = va_arg(args, bool *);
398 #if LIBAVFORMAT_VERSION_MAJOR < 54
399         *b = sys->context->prot->url_read_pause != NULL;
400 #else
401         *b = sys->context->read_pause != NULL;
402 #endif
403         return VLC_SUCCESS;
404     case ACCESS_CAN_CONTROL_PACE:
405         b = va_arg(args, bool *);
406         *b = true; /* FIXME */
407         return VLC_SUCCESS;
408     case ACCESS_GET_PTS_DELAY: {
409         int64_t *delay = va_arg(args, int64_t *);
410         *delay = DEFAULT_PTS_DELAY; /* FIXME */
411         return VLC_SUCCESS;
412     }
413     case ACCESS_SET_PAUSE_STATE: {
414         bool is_paused = va_arg(args, int);
415         if (avio_pause(sys->context, is_paused)< 0)
416             return VLC_EGENERIC;
417         return VLC_SUCCESS;
418     }
419     case ACCESS_GET_TITLE_INFO:
420     case ACCESS_GET_META:
421     case ACCESS_GET_CONTENT_TYPE:
422     case ACCESS_GET_SIGNAL:
423     case ACCESS_SET_TITLE:
424     case ACCESS_SET_SEEKPOINT:
425     case ACCESS_SET_PRIVATE_ID_STATE:
426     case ACCESS_SET_PRIVATE_ID_CA:
427     case ACCESS_GET_PRIVATE_ID_STATE:
428     default:
429         return VLC_EGENERIC;
430     }
431 }