]> git.sesse.net Git - vlc/blob - src/input/demux.c
* demux: another way to break your config file, or, --demux is now taken
[vlc] / src / input / demux.c
1 /*****************************************************************************
2  * demux.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
5  * $Id$
6  *
7  * Author: Laurent Aimar <fenrir@via.ecp.fr>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <stdlib.h>
25 #include <vlc/vlc.h>
26 #include <vlc/input.h>
27
28 #include "input_internal.h"
29
30 /*****************************************************************************
31  * demux2_New:
32  *  if s is NULL then load a access_demux
33  *****************************************************************************/
34 demux_t *__demux2_New( vlc_object_t *p_obj,
35                        char *psz_access, char *psz_demux, char *psz_path,
36                        stream_t *s, es_out_t *out )
37 {
38     demux_t *p_demux = vlc_object_create( p_obj, VLC_OBJECT_DEMUX );
39     char *psz_module;
40
41     if( p_demux == NULL )
42     {
43         return NULL;
44     }
45
46     /* Parse URL */
47     p_demux->psz_access = strdup( psz_access );
48     p_demux->psz_demux  = strdup( psz_demux );
49     p_demux->psz_path   = strdup( psz_path );
50
51     /* Take into account "demux" to be able to do :demux=demuxdump */
52     if( *p_demux->psz_demux == '\0' )
53     {
54         free( p_demux->psz_demux );
55         p_demux->psz_demux = var_GetString( p_obj, "demux" );
56     }
57
58     msg_Dbg( p_obj, "demux2_New: access='%s' demux='%s' path='%s'",
59              p_demux->psz_access, p_demux->psz_demux, p_demux->psz_path );
60
61     p_demux->s          = s;
62     p_demux->out        = out;
63
64     p_demux->pf_demux   = NULL;
65     p_demux->pf_control = NULL;
66     p_demux->p_sys      = NULL;
67     p_demux->info.i_update = 0;
68     p_demux->info.i_title  = 0;
69     p_demux->info.i_seekpoint = 0;
70
71     if( s )
72         psz_module = p_demux->psz_demux;
73     else
74         psz_module = p_demux->psz_access;
75
76     if( s && *psz_module == '\0' && strrchr( p_demux->psz_path, '.' ) )
77     {
78         /* XXX: add only file without any problem here and with strong detection.
79          *  - no .mp3, .a52, ... (aac is added as it works only by file ext anyway
80          *  - wav can't be added 'cause of a52 and dts in them as raw audio
81          */
82         static struct { char *ext; char *demux; } exttodemux[] =
83         {
84             { "aac",  "aac" },
85             { "aiff", "aiff" },
86             { "asf",  "asf" }, { "wmv",  "asf" }, { "wma",  "asf" },
87             { "avi",  "avi" },
88             { "au",   "au" },
89             { "flac", "flac" },
90             { "dv",   "dv" },
91             { "m3u",  "m3u" },
92             { "mkv",  "mkv" }, { "mka",  "mkv" }, { "mks",  "mkv" },
93             { "mp4",  "mp4" }, { "m4a",  "mp4" }, { "mov",  "mp4" }, { "moov", "mp4" },
94             { "mod",  "mod" }, { "xm",   "mod" },
95             { "nsv",  "nsv" },
96             { "ogg",  "ogg" }, { "ogm",  "ogg" },
97             { "pva",  "pva" },
98             { "rm",   "rm" },
99             { "",  "" },
100         };
101
102         char *psz_ext = strrchr( p_demux->psz_path, '.' ) + 1;
103         int  i;
104
105         for( i = 0; exttodemux[i].ext != NULL; i++ )
106         {
107             if( !strcasecmp( psz_ext, exttodemux[i].ext ) )
108             {
109                 psz_module = exttodemux[i].demux;
110                 break;
111             }
112         }
113     }
114
115     /* Before module_Need (for var_Create...) */
116     vlc_object_attach( p_demux, p_obj );
117
118     if( s )
119     {
120         p_demux->p_module =
121             module_Need( p_demux, "demux2", psz_module,
122                          !strcmp( psz_module, p_demux->psz_demux ) ? VLC_TRUE : VLC_FALSE );
123     }
124     else
125     {
126         p_demux->p_module =
127             module_Need( p_demux, "access_demux", psz_module,
128                          !strcmp( psz_module, p_demux->psz_access ) ? VLC_TRUE : VLC_FALSE );
129     }
130
131     if( p_demux->p_module == NULL )
132     {
133         vlc_object_detach( p_demux );
134         free( p_demux->psz_path );
135         free( p_demux->psz_demux );
136         free( p_demux->psz_access );
137         vlc_object_destroy( p_demux );
138         return NULL;
139     }
140
141     return p_demux;
142 }
143
144 /*****************************************************************************
145  * demux2_Delete:
146  *****************************************************************************/
147 void demux2_Delete( demux_t *p_demux )
148 {
149     module_Unneed( p_demux, p_demux->p_module );
150     vlc_object_detach( p_demux );
151
152     free( p_demux->psz_path );
153     free( p_demux->psz_demux );
154     free( p_demux->psz_access );
155
156     vlc_object_destroy( p_demux );
157 }
158
159 /*****************************************************************************
160  * demux2_vaControlHelper:
161  *****************************************************************************/
162 int demux2_vaControlHelper( stream_t *s,
163                             int64_t i_start, int64_t i_end,
164                             int i_bitrate, int i_align,
165                             int i_query, va_list args )
166 {
167     int64_t i_tell;
168     double  f, *pf;
169     int64_t i64, *pi64;
170
171     if( i_end < 0 )    i_end   = stream_Size( s );
172     if( i_start < 0 )  i_start = 0;
173     if( i_align <= 0 ) i_align = 1;
174     i_tell = stream_Tell( s );
175
176     switch( i_query )
177     {
178         case DEMUX_GET_LENGTH:
179             pi64 = (int64_t*)va_arg( args, int64_t * );
180             if( i_bitrate > 0 && i_end > i_start )
181             {
182                 *pi64 = I64C(8000000) * (i_end - i_start) / i_bitrate;
183                 return VLC_SUCCESS;
184             }
185             return VLC_EGENERIC;
186
187         case DEMUX_GET_TIME:
188             pi64 = (int64_t*)va_arg( args, int64_t * );
189             if( i_bitrate > 0 && i_end > i_start )
190             {
191                 *pi64 = I64C(8000000) * (i_tell - i_start) / i_bitrate;
192                 return VLC_SUCCESS;
193             }
194             return VLC_EGENERIC;
195
196         case DEMUX_GET_POSITION:
197             pf = (double*)va_arg( args, double * );
198             if( i_start < i_end )
199             {
200                 *pf = (double)( i_tell - i_start ) /
201                       (double)( i_end  - i_start );
202                 return VLC_SUCCESS;
203             }
204             return VLC_EGENERIC;
205
206
207         case DEMUX_SET_POSITION:
208             f = (double)va_arg( args, double );
209             if( i_start < i_end && f >= 0.0 && f <= 1.0 )
210             {
211                 int64_t i_block = (f * ( i_end - i_start )) / i_align;
212
213                 if( stream_Seek( s, i_start + i_block * i_align ) )
214                 {
215                     return VLC_EGENERIC;
216                 }
217                 return VLC_SUCCESS;
218             }
219             return VLC_EGENERIC;
220
221         case DEMUX_SET_TIME:
222             i64 = (int64_t)va_arg( args, int64_t );
223             if( i_bitrate > 0 && i64 >= 0 )
224             {
225                 int64_t i_block = i64 * i_bitrate / I64C(8000000) / i_align;
226                 if( stream_Seek( s, i_start + i_block * i_align ) )
227                 {
228                     return VLC_EGENERIC;
229                 }
230                 return VLC_SUCCESS;
231             }
232             return VLC_EGENERIC;
233
234         case DEMUX_GET_FPS:
235         case DEMUX_GET_META:
236         case DEMUX_SET_NEXT_DEMUX_TIME:
237         case DEMUX_GET_TITLE_INFO:
238             return VLC_EGENERIC;
239
240         default:
241             msg_Err( s, "unknown query in demux_vaControlDefault" );
242             return VLC_EGENERIC;
243     }
244 }
245
246 /****************************************************************************
247  * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
248  ****************************************************************************/
249 typedef struct
250 {
251     /* Data buffer */
252     vlc_mutex_t lock;
253     int         i_buffer;
254     int         i_buffer_size;
255     uint8_t     *p_buffer;
256
257     int64_t     i_pos;
258
259     /* Demuxer */
260     char        *psz_name;
261     es_out_t    *out;
262     demux_t     *p_demux;
263 } d_stream_sys_t;
264
265 static int DStreamRead   ( stream_t *, void *p_read, int i_read );
266 static int DStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
267 static int DStreamControl( stream_t *, int i_query, va_list );
268 static int DStreamThread ( stream_t * );
269
270
271 stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out )
272 {
273     /* We create a stream reader, and launch a thread */
274     stream_t       *s;
275     d_stream_sys_t *p_sys;
276
277     if( psz_demux == NULL || *psz_demux == '\0' )
278     {
279         return NULL;
280     }
281
282     s = vlc_object_create( p_obj, VLC_OBJECT_STREAM );
283     s->pf_block  = NULL;
284     s->pf_read   = DStreamRead;
285     s->pf_peek   = DStreamPeek;
286     s->pf_control= DStreamControl;
287
288     s->p_sys = malloc( sizeof( d_stream_sys_t) );
289     p_sys = (d_stream_sys_t*)s->p_sys;
290
291     vlc_mutex_init( s, &p_sys->lock );
292     p_sys->i_buffer = 0;
293     p_sys->i_buffer_size = 1000000;
294     p_sys->p_buffer = malloc( p_sys->i_buffer_size );
295     p_sys->i_pos = 0;
296     p_sys->psz_name = strdup( psz_demux );
297     p_sys->out = out;
298     p_sys->p_demux = NULL;
299
300     if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
301     {
302         vlc_mutex_destroy( &p_sys->lock );
303         vlc_object_destroy( s );
304         free( p_sys );
305         return NULL;
306     }
307
308     return s;
309 }
310
311 void     stream_DemuxSend( stream_t *s, block_t *p_block )
312 {
313     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
314
315     if( p_block->i_buffer > 0 )
316     {
317         vlc_mutex_lock( &p_sys->lock );
318         /* Realloc if needed */
319         if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
320         {
321             if( p_sys->i_buffer_size > 5000000 )
322             {
323                 vlc_mutex_unlock( &p_sys->lock );
324                 msg_Err( s, "stream_DemuxSend: buffer size > 5000000" );
325                 block_Release( p_block );
326                 return;
327             }
328             /* I know, it's more than needed but that's perfect */
329             p_sys->i_buffer_size += p_block->i_buffer;
330             /* FIXME won't work with PEEK -> segfault */
331             p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
332             msg_Dbg( s, "stream_DemuxSend: realloc to %d", p_sys->i_buffer_size );
333         }
334
335         /* copy data */
336         memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer );
337         p_sys->i_buffer += p_block->i_buffer;
338
339         vlc_mutex_unlock( &p_sys->lock );
340     }
341
342     block_Release( p_block );
343 }
344
345 void     stream_DemuxDelete( stream_t *s )
346 {
347     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
348
349     s->b_die = VLC_TRUE;
350
351     vlc_mutex_lock( &p_sys->lock );
352     if( p_sys->p_demux )
353     {
354         p_sys->p_demux->b_die = VLC_TRUE;
355     }
356     vlc_mutex_unlock( &p_sys->lock );
357
358     vlc_thread_join( s );
359
360     if( p_sys->p_demux )
361     {
362         demux2_Delete( p_sys->p_demux );
363     }
364     vlc_mutex_destroy( &p_sys->lock );
365     free( p_sys->psz_name );
366     free( p_sys->p_buffer );
367     free( p_sys );
368     vlc_object_destroy( s );
369 }
370
371
372 static int      DStreamRead   ( stream_t *s, void *p_read, int i_read )
373 {
374     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
375     int           i_copy;
376
377     //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
378     for( ;; )
379     {
380         vlc_mutex_lock( &p_sys->lock );
381         //msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer );
382         if( p_sys->i_buffer >= i_read || s->b_die )
383         {
384             break;
385         }
386         vlc_mutex_unlock( &p_sys->lock );
387         msleep( 10000 );
388     }
389
390     //msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
391
392     i_copy = __MIN( i_read, p_sys->i_buffer );
393     if( i_copy > 0 )
394     {
395         if( p_read )
396         {
397             memcpy( p_read, p_sys->p_buffer, i_copy );
398         }
399         p_sys->i_buffer -= i_copy;
400         p_sys->i_pos += i_copy;
401
402         if( p_sys->i_buffer > 0 )
403         {
404             memmove( p_sys->p_buffer, &p_sys->p_buffer[i_copy], p_sys->i_buffer );
405         }
406
407     }
408     vlc_mutex_unlock( &p_sys->lock );
409
410     return i_copy;
411 }
412 static int      DStreamPeek   ( stream_t *s, uint8_t **pp_peek, int i_peek )
413 {
414     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
415     int           i_copy;
416
417     //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
418     for( ;; )
419     {
420         vlc_mutex_lock( &p_sys->lock );
421         //msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
422         if( p_sys->i_buffer >= i_peek || s->b_die )
423         {
424             break;
425         }
426         vlc_mutex_unlock( &p_sys->lock );
427         msleep( 10000 );
428     }
429     *pp_peek = p_sys->p_buffer;
430     i_copy = __MIN( i_peek, p_sys->i_buffer );
431
432     vlc_mutex_unlock( &p_sys->lock );
433
434     return i_copy;
435 }
436
437 static int      DStreamControl( stream_t *s, int i_query, va_list args )
438 {
439     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
440     int64_t    *p_i64;
441     vlc_bool_t *p_b;
442     int        *p_int;
443     switch( i_query )
444     {
445         case STREAM_GET_SIZE:
446             p_i64 = (int64_t*) va_arg( args, int64_t * );
447             *p_i64 = 0;
448             return VLC_SUCCESS;
449
450         case STREAM_CAN_SEEK:
451             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
452             *p_b = VLC_FALSE;
453             return VLC_SUCCESS;
454
455         case STREAM_CAN_FASTSEEK:
456             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
457             *p_b = VLC_FALSE;
458             return VLC_SUCCESS;
459
460         case STREAM_GET_POSITION:
461             p_i64 = (int64_t*) va_arg( args, int64_t * );
462             *p_i64 = p_sys->i_pos;
463             return VLC_SUCCESS;
464
465         case STREAM_SET_POSITION:
466         {
467             int64_t i64 = (int64_t)va_arg( args, int64_t );
468             int i_skip;
469             if( i64 < p_sys->i_pos )
470                 return VLC_EGENERIC;
471             i_skip = i64 - p_sys->i_pos;
472
473             while( i_skip > 0 )
474             {
475                 int i_read = DStreamRead( s, NULL, i_skip );
476
477                 if( i_read <= 0 )
478                     return VLC_EGENERIC;
479
480                 i_skip -= i_read;
481             }
482             return VLC_SUCCESS;
483         }
484
485         case STREAM_GET_MTU:
486             p_int = (int*) va_arg( args, int * );
487             *p_int = 0;
488             return VLC_SUCCESS;
489
490         default:
491             msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
492             return VLC_EGENERIC;
493     }
494 }
495
496 static int      DStreamThread ( stream_t *s )
497 {
498     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
499     demux_t      *p_demux;
500
501     /* Create the demuxer */
502
503     if( ( p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out ) ) == NULL )
504     {
505         return VLC_EGENERIC;
506     }
507
508     vlc_mutex_lock( &p_sys->lock );
509     p_sys->p_demux = p_demux;
510     vlc_mutex_unlock( &p_sys->lock );
511
512     /* Main loop */
513     while( !s->b_die && !p_demux->b_die )
514     {
515         if( p_demux->pf_demux( p_demux ) <= 0 )
516         {
517             break;
518         }
519     }
520     p_demux->b_die = VLC_TRUE;
521     return VLC_SUCCESS;
522 }