]> git.sesse.net Git - vlc/blob - modules/access/avio.c
mux: ogg: add daala support
[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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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 #include "../codec/avcodec/avcommon.h"
37
38 #if LIBAVFORMAT_VERSION_MAJOR < 54
39 # define AVIOContext URLContext
40
41 # define avio_open url_open
42 # define avio_close url_close
43 # define avio_read url_read
44 # define avio_seek url_seek
45 # define avio_pause av_url_read_pause
46
47 # define AVIO_FLAG_READ URL_RDONLY
48 # define AVIO_FLAG_WRITE URL_WRONLY
49 # define avio_size url_filesize
50 #endif
51
52 /*****************************************************************************
53  * Module descriptor
54  *****************************************************************************/
55 #ifndef MERGE_FFMPEG
56 vlc_module_begin()
57     AVIO_MODULE
58 vlc_module_end()
59 #endif
60
61 /*****************************************************************************
62  * Local prototypes
63  *****************************************************************************/
64 static ssize_t Read   (access_t *, uint8_t *, size_t);
65 static int     Seek   (access_t *, uint64_t);
66 static int     Control(access_t *, int, va_list);
67 static ssize_t Write(sout_access_out_t *, block_t *);
68 static int     OutControl(sout_access_out_t *, int, va_list);
69 static int     OutSeek (sout_access_out_t *, off_t);
70
71 static int UrlInterruptCallback(void *access)
72 {
73     return !vlc_object_alive((vlc_object_t*)access);
74 }
75
76 struct access_sys_t
77 {
78     AVIOContext *context;
79     uint64_t size;
80 };
81
82 struct sout_access_out_sys_t {
83     AVIOContext *context;
84 };
85
86
87 /* */
88
89 #if LIBAVFORMAT_VERSION_MAJOR < 54
90 static vlc_object_t *current_access = NULL;
91
92 static int UrlInterruptCallbackSingle(void)
93 {
94     return UrlInterruptCallback(current_access);
95 }
96
97 static int SetupAvioCb(vlc_object_t *access)
98 {
99     static vlc_mutex_t avio_lock = VLC_STATIC_MUTEX;
100     vlc_mutex_lock(&avio_lock);
101     assert(!access != !current_access);
102     if (access && current_access) {
103         vlc_mutex_unlock(&avio_lock);
104         return VLC_EGENERIC;
105     }
106     url_set_interrupt_cb(access ? UrlInterruptCallbackSingle : NULL);
107
108     current_access = access;
109
110     vlc_mutex_unlock(&avio_lock);
111
112     return VLC_SUCCESS;
113 }
114 #endif
115
116 /* */
117
118 int OpenAvio(vlc_object_t *object)
119 {
120     access_t *access = (access_t*)object;
121     access_sys_t *sys = malloc(sizeof(*sys));
122     if (!sys)
123         return VLC_ENOMEM;
124     sys->context = NULL;
125
126     /* We accept:
127      * - avio://full_url
128      * - url (only a subset of available protocols).
129      */
130     char *url;
131     if (!strcmp(access->psz_access, "avio"))
132         url = strdup(access->psz_location);
133     else if (asprintf(&url, "%s://%s", access->psz_access,
134                       access->psz_location) < 0)
135         url = NULL;
136
137     if (!url) {
138         free(sys);
139         return VLC_ENOMEM;
140     }
141
142     /* */
143     vlc_init_avformat(object);
144
145     int ret;
146 #if LIBAVFORMAT_VERSION_MAJOR < 54
147     ret = avio_open(&sys->context, url, AVIO_FLAG_READ);
148 #else
149     AVIOInterruptCB cb = {
150         .callback = UrlInterruptCallback,
151         .opaque = access,
152     };
153     AVDictionary *options = NULL;
154     char *psz_opts = var_InheritString(access, "avio-options");
155     if (psz_opts && *psz_opts) {
156         options = vlc_av_get_options(psz_opts);
157         free(psz_opts);
158     }
159     ret = avio_open2(&sys->context, url, AVIO_FLAG_READ, &cb, &options);
160     AVDictionaryEntry *t = NULL;
161     while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX)))
162         msg_Err( access, "unknown option \"%s\"", t->key );
163     av_dict_free(&options);
164 #endif
165     if (ret < 0) {
166         msg_Err(access, "Failed to open %s: %s", url,
167                 vlc_strerror_c(AVUNERROR(ret)));
168         free(url);
169         goto error;
170     }
171     free(url);
172
173 #if LIBAVFORMAT_VERSION_MAJOR < 54
174     /* We can accept only one active user at any time */
175     if (SetupAvioCb(VLC_OBJECT(access))) {
176         msg_Err(access, "Module aready in use");
177         avio_close(sys->context);
178         goto error;
179     }
180 #endif
181
182     int64_t size = avio_size(sys->context);
183     bool seekable;
184 #if LIBAVFORMAT_VERSION_MAJOR < 54
185     seekable = !sys->context->is_streamed;
186 #else
187     seekable = sys->context->seekable;
188 #endif
189     msg_Dbg(access, "%sseekable, size=%"PRIi64, seekable ? "" : "not ", size);
190     sys->size = size > 0 ? size : 0;
191
192     /* */
193     access_InitFields(access);
194
195     access->pf_read = Read;
196     access->pf_block = NULL;
197     access->pf_control = Control;
198     access->pf_seek = Seek;
199     access->p_sys = sys;
200
201     return VLC_SUCCESS;
202
203 error:
204     free(sys);
205     return VLC_EGENERIC;
206 }
207
208 /* */
209
210 static const char *const ppsz_sout_options[] = {
211     "options",
212     NULL,
213 };
214
215 int OutOpenAvio(vlc_object_t *object)
216 {
217     sout_access_out_t *access = (sout_access_out_t*)object;
218
219     config_ChainParse( access, "sout-avio-", ppsz_sout_options, access->p_cfg );
220
221     sout_access_out_sys_t *sys = malloc(sizeof(*sys));
222     if (!sys)
223         return VLC_ENOMEM;
224     sys->context = NULL;
225
226     /* */
227     vlc_init_avformat(object);
228
229     if (!access->psz_path)
230         goto error;
231
232     int ret;
233 #if LIBAVFORMAT_VERSION_MAJOR < 54
234     ret = avio_open(&sys->context, access->psz_path, AVIO_FLAG_WRITE);
235 #else
236     AVIOInterruptCB cb = {
237         .callback = UrlInterruptCallback,
238         .opaque = access,
239     };
240     AVDictionary *options = NULL;
241     char *psz_opts = var_InheritString(access, "sout-avio-options");
242     if (psz_opts && *psz_opts) {
243         options = vlc_av_get_options(psz_opts);
244         free(psz_opts);
245     }
246     ret = avio_open2(&sys->context, access->psz_path, AVIO_FLAG_WRITE,
247                      &cb, &options);
248     AVDictionaryEntry *t = NULL;
249     while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX)))
250         msg_Err( access, "unknown option \"%s\"", t->key );
251     av_dict_free(&options);
252 #endif
253     if (ret < 0) {
254         errno = AVUNERROR(ret);
255         msg_Err(access, "Failed to open %s", access->psz_path);
256         goto error;
257     }
258
259 #if LIBAVFORMAT_VERSION_MAJOR < 54
260     /* We can accept only one active user at any time */
261     if (SetupAvioCb(VLC_OBJECT(access))) {
262         msg_Err(access, "Module aready in use");
263         goto error;
264     }
265 #endif
266
267     access->pf_write = Write;
268     access->pf_control = OutControl;
269     access->pf_seek = OutSeek;
270     access->p_sys = sys;
271
272     return VLC_SUCCESS;
273
274 error:
275     free(sys);
276     return VLC_EGENERIC;
277 }
278
279 void CloseAvio(vlc_object_t *object)
280 {
281     access_t *access = (access_t*)object;
282     access_sys_t *sys = access->p_sys;
283
284 #if LIBAVFORMAT_VERSION_MAJOR < 54
285     SetupAvioCb(NULL);
286 #endif
287
288     avio_close(sys->context);
289     free(sys);
290 }
291
292 void OutCloseAvio(vlc_object_t *object)
293 {
294     sout_access_out_t *access = (sout_access_out_t*)object;
295     sout_access_out_sys_t *sys = access->p_sys;
296
297 #if LIBAVFORMAT_VERSION_MAJOR < 54
298     SetupAvioCb(NULL);
299 #endif
300
301     avio_close(sys->context);
302     free(sys);
303 }
304
305 static ssize_t Read(access_t *access, uint8_t *data, size_t size)
306 {
307     int r = avio_read(access->p_sys->context, data, size);
308     if (r > 0)
309         access->info.i_pos += r;
310     else {
311         access->info.b_eof = true;
312         r = 0;
313     }
314     return r;
315 }
316
317 /*****************************************************************************
318  * Write:
319  *****************************************************************************/
320 static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer)
321 {
322     sout_access_out_sys_t *p_sys = (sout_access_out_sys_t*)p_access->p_sys;
323     size_t i_write = 0;
324     int val;
325
326     while (p_buffer != NULL) {
327         block_t *p_next = p_buffer->p_next;
328
329 #if LIBAVFORMAT_VERSION_MAJOR < 54
330         val = url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
331         if (val < 0)
332             goto error;
333         i_write += val;
334 #else
335         avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
336         avio_flush(p_sys->context);
337         if ((val = p_sys->context->error) != 0) {
338             p_sys->context->error = 0; /* FIXME? */
339             goto error;
340         }
341         i_write += p_buffer->i_buffer;
342 #endif
343
344         block_Release(p_buffer);
345
346         p_buffer = p_next;
347     }
348
349     return i_write;
350
351 error:
352     msg_Err(p_access, "Wrote only %zu bytes: %s", i_write,
353             vlc_strerror_c(AVUNERROR(val)));
354     block_ChainRelease( p_buffer );
355     return i_write;
356 }
357
358 static int Seek(access_t *access, uint64_t position)
359 {
360     access_sys_t *sys = access->p_sys;
361     int ret;
362
363 #ifndef EOVERFLOW
364 # define EOVERFLOW EFBIG
365 #endif
366
367     if (position > INT64_MAX)
368         ret = AVERROR(EOVERFLOW);
369     else
370         ret = avio_seek(sys->context, position, SEEK_SET);
371     if (ret < 0) {
372         msg_Err(access, "Seek to %"PRIu64" failed: %s", position,
373                 vlc_strerror_c(AVUNERROR(ret)));
374         if (sys->size == 0 || position != sys->size)
375             return VLC_EGENERIC;
376     }
377     access->info.i_pos = position;
378     access->info.b_eof = false;
379     return VLC_SUCCESS;
380 }
381
382 static int OutSeek(sout_access_out_t *p_access, off_t i_pos)
383 {
384     sout_access_out_sys_t *sys = p_access->p_sys;
385
386     if (avio_seek(sys->context, i_pos, SEEK_SET) < 0)
387         return VLC_EGENERIC;
388     return VLC_SUCCESS;
389 }
390
391 static int OutControl(sout_access_out_t *p_access, int i_query, va_list args)
392 {
393     sout_access_out_sys_t *p_sys = p_access->p_sys;
394
395     VLC_UNUSED(p_sys);
396     switch (i_query) {
397     case ACCESS_OUT_CONTROLS_PACE: {
398         bool *pb = va_arg(args, bool *);
399         //*pb = strcmp(p_access->psz_access, "stream");
400         *pb = false;
401         break;
402     }
403
404     default:
405         return VLC_EGENERIC;
406     }
407     return VLC_SUCCESS;
408 }
409
410 static int Control(access_t *access, int query, va_list args)
411 {
412     access_sys_t *sys = access->p_sys;
413     bool *b;
414
415     switch (query) {
416     case ACCESS_CAN_SEEK:
417     case ACCESS_CAN_FASTSEEK: /* FIXME how to do that ? */
418         b = va_arg(args, bool *);
419 #if LIBAVFORMAT_VERSION_MAJOR < 54
420         *b = !sys->context->is_streamed;
421 #else
422         *b = sys->context->seekable;
423 #endif
424         return VLC_SUCCESS;
425     case ACCESS_CAN_PAUSE:
426         b = va_arg(args, bool *);
427 #if LIBAVFORMAT_VERSION_MAJOR < 54
428         *b = sys->context->prot->url_read_pause != NULL;
429 #else
430         *b = sys->context->read_pause != NULL;
431 #endif
432         return VLC_SUCCESS;
433     case ACCESS_CAN_CONTROL_PACE:
434         b = va_arg(args, bool *);
435         *b = true; /* FIXME */
436         return VLC_SUCCESS;
437     case ACCESS_GET_SIZE:
438         *va_arg(args, uint64_t *) = sys->size;
439         return VLC_SUCCESS;
440     case ACCESS_GET_PTS_DELAY: {
441         int64_t *delay = va_arg(args, int64_t *);
442         *delay = INT64_C(1000) * var_InheritInteger(access, "network-caching");
443         return VLC_SUCCESS;
444     }
445     case ACCESS_SET_PAUSE_STATE: {
446         bool is_paused = va_arg(args, int);
447         if (avio_pause(sys->context, is_paused)< 0)
448             return VLC_EGENERIC;
449         return VLC_SUCCESS;
450     }
451     default:
452         return VLC_EGENERIC;
453     }
454 }