]> git.sesse.net Git - vlc/blob - modules/access/avio.c
libav*: move avformat/avcodec init to a single header file
[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 #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     AVIOContext *context;
78 };
79
80 struct sout_access_out_sys_t {
81     AVIOContext *context;
82 };
83
84
85 /* */
86
87 #if LIBAVFORMAT_VERSION_MAJOR < 54
88 static vlc_object_t *current_access = NULL;
89
90 static int UrlInterruptCallbackSingle(void)
91 {
92     return UrlInterruptCallback(current_access);
93 }
94
95 static int SetupAvioCb(vlc_object_t *access)
96 {
97     static vlc_mutex_t avio_lock = VLC_STATIC_MUTEX;
98     vlc_mutex_lock(&avio_lock);
99     assert(!access != !current_access);
100     if (access && current_access) {
101         vlc_mutex_unlock(&avio_lock);
102         return VLC_EGENERIC;
103     }
104     url_set_interrupt_cb(access ? UrlInterruptCallbackSingle : NULL);
105
106     current_access = access;
107
108     vlc_mutex_unlock(&avio_lock);
109
110     return VLC_SUCCESS;
111 }
112 #endif
113
114 /* */
115
116 int OpenAvio(vlc_object_t *object)
117 {
118     access_t *access = (access_t*)object;
119     access_sys_t *sys = malloc(sizeof(*sys));
120     if (!sys)
121         return VLC_ENOMEM;
122     sys->context = NULL;
123
124     /* We accept:
125      * - avio://full_url
126      * - url (only a subset of available protocols).
127      */
128     char *url;
129     if (!strcmp(access->psz_access, "avio"))
130         url = strdup(access->psz_location);
131     else if (asprintf(&url, "%s://%s", access->psz_access,
132                       access->psz_location) < 0)
133         url = NULL;
134
135     if (!url) {
136         free(sys);
137         return VLC_ENOMEM;
138     }
139
140     /* */
141     vlc_init_avformat();
142
143     int ret;
144 #if LIBAVFORMAT_VERSION_MAJOR < 54
145     ret = avio_open(&sys->context, url, AVIO_FLAG_READ);
146 #else
147     AVIOInterruptCB cb = {
148         .callback = UrlInterruptCallback,
149         .opaque = access,
150     };
151     ret = avio_open2(&sys->context, url, AVIO_FLAG_READ, &cb, NULL /* options */);
152 #endif
153     if (ret < 0) {
154         errno = AVUNERROR(ret);
155         msg_Err(access, "Failed to open %s: %m", url);
156         free(url);
157         goto error;
158     }
159     free(url);
160
161 #if LIBAVFORMAT_VERSION_MAJOR < 54
162     /* We can accept only one active user at any time */
163     if (SetupAvioCb(VLC_OBJECT(access))) {
164         msg_Err(access, "Module aready in use");
165         avio_close(sys->context);
166         goto error;
167     }
168 #endif
169
170     int64_t size = avio_size(sys->context);
171     bool seekable;
172 #if LIBAVFORMAT_VERSION_MAJOR < 54
173     seekable = !sys->context->is_streamed;
174 #else
175     seekable = sys->context->seekable;
176 #endif
177     msg_Dbg(access, "%sseekable, size=%"PRIi64, seekable ? "" : "not ", size);
178
179     /* */
180     access_InitFields(access);
181     access->info.i_size = size > 0 ? size : 0;
182
183     access->pf_read = Read;
184     access->pf_block = NULL;
185     access->pf_control = Control;
186     access->pf_seek = Seek;
187     access->p_sys = sys;
188
189     return VLC_SUCCESS;
190
191 error:
192     free(sys);
193     return VLC_EGENERIC;
194 }
195
196 /* */
197 int OutOpenAvio(vlc_object_t *object)
198 {
199     sout_access_out_t *access = (sout_access_out_t*)object;
200     sout_access_out_sys_t *sys = malloc(sizeof(*sys));
201     if (!sys)
202         return VLC_ENOMEM;
203     sys->context = NULL;
204
205     /* */
206     vlc_init_avformat();
207
208     if (!access->psz_path)
209         goto error;
210
211     int ret;
212 #if LIBAVFORMAT_VERSION_MAJOR < 54
213     ret = avio_open(&sys->context, access->psz_path, AVIO_FLAG_WRITE);
214 #else
215     AVIOInterruptCB cb = {
216         .callback = UrlInterruptCallback,
217         .opaque = access,
218     };
219     ret = avio_open2(&sys->context, access->psz_path, AVIO_FLAG_WRITE,
220                      &cb, NULL /* options */);
221 #endif
222     if (ret < 0) {
223         errno = AVUNERROR(ret);
224         msg_Err(access, "Failed to open %s", access->psz_path);
225         goto error;
226     }
227
228 #if LIBAVFORMAT_VERSION_MAJOR < 54
229     /* We can accept only one active user at any time */
230     if (SetupAvioCb(VLC_OBJECT(access))) {
231         msg_Err(access, "Module aready in use");
232         goto error;
233     }
234 #endif
235
236     access->pf_write = Write;
237     access->pf_control = OutControl;
238     access->pf_seek = OutSeek;
239     access->p_sys = sys;
240
241     return VLC_SUCCESS;
242
243 error:
244     free(sys);
245     return VLC_EGENERIC;
246 }
247
248 void CloseAvio(vlc_object_t *object)
249 {
250     access_t *access = (access_t*)object;
251     access_sys_t *sys = access->p_sys;
252
253 #if LIBAVFORMAT_VERSION_MAJOR < 54
254     SetupAvioCb(NULL);
255 #endif
256
257     avio_close(sys->context);
258     free(sys);
259 }
260
261 void OutCloseAvio(vlc_object_t *object)
262 {
263     sout_access_out_t *access = (sout_access_out_t*)object;
264     sout_access_out_sys_t *sys = access->p_sys;
265
266 #if LIBAVFORMAT_VERSION_MAJOR < 54
267     SetupAvioCb(NULL);
268 #endif
269
270     avio_close(sys->context);
271     free(sys);
272 }
273
274 static ssize_t Read(access_t *access, uint8_t *data, size_t size)
275 {
276     int r = avio_read(access->p_sys->context, data, size);
277     if (r > 0)
278         access->info.i_pos += r;
279     else
280         access->info.b_eof = true;
281     return r;
282 }
283
284 /*****************************************************************************
285  * Write:
286  *****************************************************************************/
287 static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer)
288 {
289     access_sys_t *p_sys = (access_sys_t*)p_access->p_sys;
290     size_t i_write = 0;
291
292     while (p_buffer != NULL) {
293         block_t *p_next = p_buffer->p_next;
294
295 #if LIBAVFORMAT_VERSION_MAJOR < 54
296         int written = url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
297         if (written < 0) {
298             errno = AVUNERROR(written);
299             goto error;
300         }
301         i_write += written;
302 #else
303         avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer);
304         avio_flush(p_sys->context);
305         if (p_sys->context->error) {
306             errno = AVUNERROR(p_sys->context->error);
307             p_sys->context->error = 0; /* FIXME? */
308             goto error;
309         }
310         i_write += p_buffer->i_buffer;
311 #endif
312
313         block_Release(p_buffer);
314
315         p_buffer = p_next;
316     }
317
318     return i_write;
319
320 error:
321     msg_Err(p_access, "Wrote only %zu bytes (%m)", i_write);
322     block_ChainRelease( p_buffer );
323     return i_write;
324 }
325
326 static int Seek(access_t *access, uint64_t position)
327 {
328     access_sys_t *sys = access->p_sys;
329     int ret;
330
331 #ifndef EOVERFLOW
332 # define EOVERFLOW EFBIG
333 #endif
334
335     if (position > INT64_MAX)
336         ret = AVERROR(EOVERFLOW);
337     else
338         ret = avio_seek(sys->context, position, SEEK_SET);
339     if (ret < 0) {
340         errno = AVUNERROR(ret);
341         msg_Err(access, "Seek to %"PRIu64" failed: %m", position);
342         if (access->info.i_size <= 0 || position != access->info.i_size)
343             return VLC_EGENERIC;
344     }
345     access->info.i_pos = position;
346     access->info.b_eof = false;
347     return VLC_SUCCESS;
348 }
349
350 static int OutSeek(sout_access_out_t *p_access, off_t i_pos)
351 {
352     sout_access_out_sys_t *sys = p_access->p_sys;
353
354     if (avio_seek(sys->context, i_pos, SEEK_SET) < 0)
355         return VLC_EGENERIC;
356     return VLC_SUCCESS;
357 }
358
359 static int OutControl(sout_access_out_t *p_access, int i_query, va_list args)
360 {
361     sout_access_out_sys_t *p_sys = p_access->p_sys;
362
363     VLC_UNUSED(p_sys);
364     switch (i_query) {
365     case ACCESS_OUT_CONTROLS_PACE: {
366         bool *pb = va_arg(args, bool *);
367         //*pb = strcmp(p_access->psz_access, "stream");
368         *pb = false;
369         break;
370     }
371
372     default:
373         return VLC_EGENERIC;
374     }
375     return VLC_SUCCESS;
376 }
377
378 static int Control(access_t *access, int query, va_list args)
379 {
380     access_sys_t *sys = access->p_sys;
381     bool *b;
382
383     switch (query) {
384     case ACCESS_CAN_SEEK:
385     case ACCESS_CAN_FASTSEEK: /* FIXME how to do that ? */
386         b = va_arg(args, bool *);
387 #if LIBAVFORMAT_VERSION_MAJOR < 54
388         *b = !sys->context->is_streamed;
389 #else
390         *b = sys->context->seekable;
391 #endif
392         return VLC_SUCCESS;
393     case ACCESS_CAN_PAUSE:
394         b = va_arg(args, bool *);
395 #if LIBAVFORMAT_VERSION_MAJOR < 54
396         *b = sys->context->prot->url_read_pause != NULL;
397 #else
398         *b = sys->context->read_pause != NULL;
399 #endif
400         return VLC_SUCCESS;
401     case ACCESS_CAN_CONTROL_PACE:
402         b = va_arg(args, bool *);
403         *b = true; /* FIXME */
404         return VLC_SUCCESS;
405     case ACCESS_GET_PTS_DELAY: {
406         int64_t *delay = va_arg(args, int64_t *);
407         *delay = DEFAULT_PTS_DELAY; /* FIXME */
408         return VLC_SUCCESS;
409     }
410     case ACCESS_SET_PAUSE_STATE: {
411         bool is_paused = va_arg(args, int);
412         if (avio_pause(sys->context, is_paused)< 0)
413             return VLC_EGENERIC;
414         return VLC_SUCCESS;
415     }
416     case ACCESS_GET_TITLE_INFO:
417     case ACCESS_GET_META:
418     case ACCESS_GET_CONTENT_TYPE:
419     case ACCESS_GET_SIGNAL:
420     case ACCESS_SET_TITLE:
421     case ACCESS_SET_SEEKPOINT:
422     case ACCESS_SET_PRIVATE_ID_STATE:
423     case ACCESS_SET_PRIVATE_ID_CA:
424     case ACCESS_GET_PRIVATE_ID_STATE:
425     default:
426         return VLC_EGENERIC;
427     }
428 }