]> git.sesse.net Git - vlc/blob - modules/access/avio.c
vpx: fix leak
[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((access_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     AVDictionary *options = NULL;
237     char *psz_opts = var_InheritString(access, "sout-avio-options");
238     if (psz_opts && *psz_opts) {
239         options = vlc_av_get_options(psz_opts);
240         free(psz_opts);
241     }
242     ret = avio_open2(&sys->context, access->psz_path, AVIO_FLAG_WRITE,
243                      NULL, &options);
244     AVDictionaryEntry *t = NULL;
245     while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX)))
246         msg_Err( access, "unknown option \"%s\"", t->key );
247     av_dict_free(&options);
248 #endif
249     if (ret < 0) {
250         errno = AVUNERROR(ret);
251         msg_Err(access, "Failed to open %s", access->psz_path);
252         goto error;
253     }
254
255 #if LIBAVFORMAT_VERSION_MAJOR < 54
256     /* We can accept only one active user at any time */
257     if (SetupAvioCb(VLC_OBJECT(access))) {
258         msg_Err(access, "Module aready in use");
259         goto error;
260     }
261 #endif
262
263     access->pf_write = Write;
264     access->pf_control = OutControl;
265     access->pf_seek = OutSeek;
266     access->p_sys = sys;
267
268     return VLC_SUCCESS;
269
270 error:
271     free(sys);
272     return VLC_EGENERIC;
273 }
274
275 void CloseAvio(vlc_object_t *object)
276 {
277     access_t *access = (access_t*)object;
278     access_sys_t *sys = access->p_sys;
279
280 #if LIBAVFORMAT_VERSION_MAJOR < 54
281     SetupAvioCb(NULL);
282 #endif
283
284     avio_close(sys->context);
285     free(sys);
286 }
287
288 void OutCloseAvio(vlc_object_t *object)
289 {
290     sout_access_out_t *access = (sout_access_out_t*)object;
291     sout_access_out_sys_t *sys = access->p_sys;
292
293 #if LIBAVFORMAT_VERSION_MAJOR < 54
294     SetupAvioCb(NULL);
295 #endif
296
297     avio_close(sys->context);
298     free(sys);
299 }
300
301 static ssize_t Read(access_t *access, uint8_t *data, size_t size)
302 {
303     int r = avio_read(access->p_sys->context, data, size);
304     if (r > 0)
305         access->info.i_pos += r;
306     else {
307         access->info.b_eof = true;
308         r = 0;
309     }
310     return r;
311 }
312
313 /*****************************************************************************
314  * Write:
315  *****************************************************************************/
316 static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer)
317 {
318     sout_access_out_sys_t *p_sys = (sout_access_out_sys_t*)p_access->p_sys;
319     size_t i_write = 0;
320     int val;
321
322     while (p_buffer != NULL) {
323         block_t *p_next = p_buffer->p_next;
324
325 #if LIBAVFORMAT_VERSION_MAJOR < 54
326         val = url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
327         if (val < 0)
328             goto error;
329         i_write += val;
330 #else
331         avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
332         avio_flush(p_sys->context);
333         if ((val = p_sys->context->error) != 0) {
334             p_sys->context->error = 0; /* FIXME? */
335             goto error;
336         }
337         i_write += p_buffer->i_buffer;
338 #endif
339
340         block_Release(p_buffer);
341
342         p_buffer = p_next;
343     }
344
345     return i_write;
346
347 error:
348     msg_Err(p_access, "Wrote only %zu bytes: %s", i_write,
349             vlc_strerror_c(AVUNERROR(val)));
350     block_ChainRelease( p_buffer );
351     return i_write;
352 }
353
354 static int Seek(access_t *access, uint64_t position)
355 {
356     access_sys_t *sys = access->p_sys;
357     int ret;
358
359 #ifndef EOVERFLOW
360 # define EOVERFLOW EFBIG
361 #endif
362
363     if (position > INT64_MAX)
364         ret = AVERROR(EOVERFLOW);
365     else
366         ret = avio_seek(sys->context, position, SEEK_SET);
367     if (ret < 0) {
368         msg_Err(access, "Seek to %"PRIu64" failed: %s", position,
369                 vlc_strerror_c(AVUNERROR(ret)));
370         if (sys->size == 0 || position != sys->size)
371             return VLC_EGENERIC;
372     }
373     access->info.i_pos = position;
374     access->info.b_eof = false;
375     return VLC_SUCCESS;
376 }
377
378 static int OutSeek(sout_access_out_t *p_access, off_t i_pos)
379 {
380     sout_access_out_sys_t *sys = p_access->p_sys;
381
382     if (avio_seek(sys->context, i_pos, SEEK_SET) < 0)
383         return VLC_EGENERIC;
384     return VLC_SUCCESS;
385 }
386
387 static int OutControl(sout_access_out_t *p_access, int i_query, va_list args)
388 {
389     sout_access_out_sys_t *p_sys = p_access->p_sys;
390
391     VLC_UNUSED(p_sys);
392     switch (i_query) {
393     case ACCESS_OUT_CONTROLS_PACE: {
394         bool *pb = va_arg(args, bool *);
395         //*pb = strcmp(p_access->psz_access, "stream");
396         *pb = false;
397         break;
398     }
399
400     default:
401         return VLC_EGENERIC;
402     }
403     return VLC_SUCCESS;
404 }
405
406 static int Control(access_t *access, int query, va_list args)
407 {
408     access_sys_t *sys = access->p_sys;
409     bool *b;
410
411     switch (query) {
412     case ACCESS_CAN_SEEK:
413     case ACCESS_CAN_FASTSEEK: /* FIXME how to do that ? */
414         b = va_arg(args, bool *);
415 #if LIBAVFORMAT_VERSION_MAJOR < 54
416         *b = !sys->context->is_streamed;
417 #else
418         *b = sys->context->seekable;
419 #endif
420         return VLC_SUCCESS;
421     case ACCESS_CAN_PAUSE:
422         b = va_arg(args, bool *);
423 #if LIBAVFORMAT_VERSION_MAJOR < 54
424         *b = sys->context->prot->url_read_pause != NULL;
425 #else
426         *b = sys->context->read_pause != NULL;
427 #endif
428         return VLC_SUCCESS;
429     case ACCESS_CAN_CONTROL_PACE:
430         b = va_arg(args, bool *);
431         *b = true; /* FIXME */
432         return VLC_SUCCESS;
433     case ACCESS_GET_SIZE:
434         *va_arg(args, uint64_t *) = sys->size;
435         return VLC_SUCCESS;
436     case ACCESS_GET_PTS_DELAY: {
437         int64_t *delay = va_arg(args, int64_t *);
438         *delay = INT64_C(1000) * var_InheritInteger(access, "network-caching");
439         return VLC_SUCCESS;
440     }
441     case ACCESS_SET_PAUSE_STATE: {
442         bool is_paused = va_arg(args, int);
443         if (avio_pause(sys->context, is_paused)< 0)
444             return VLC_EGENERIC;
445         return VLC_SUCCESS;
446     }
447     default:
448         return VLC_EGENERIC;
449     }
450 }