]> git.sesse.net Git - vlc/blob - src/input/demux.c
3d997cfe408eb13a0323d26b1cb1060eb3111543
[vlc] / src / input / demux.c
1 /*****************************************************************************
2  * demux.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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 static void SkipID3Tag( demux_t * );
31
32 /*****************************************************************************
33  * demux2_New:
34  *  if s is NULL then load a access_demux
35  *****************************************************************************/
36 demux_t *__demux2_New( vlc_object_t *p_obj,
37                        char *psz_access, char *psz_demux, char *psz_path,
38                        stream_t *s, es_out_t *out, vlc_bool_t b_quick )
39 {
40     demux_t *p_demux = vlc_object_create( p_obj, VLC_OBJECT_DEMUX );
41     char *psz_module;
42
43     if( p_demux == NULL ) return NULL;
44
45     /* Parse URL */
46     p_demux->psz_access = strdup( psz_access );
47     p_demux->psz_demux  = strdup( psz_demux );
48     p_demux->psz_path   = strdup( psz_path );
49
50     /* Take into account "demux" to be able to do :demux=dump */
51     if( *p_demux->psz_demux == '\0' )
52     {
53         free( p_demux->psz_demux );
54         p_demux->psz_demux = var_GetString( p_obj, "demux" );
55     }
56
57     if( !b_quick )
58     {
59         msg_Dbg( p_obj, "creating demux: access='%s' demux='%s' path='%s'",
60                  p_demux->psz_access, p_demux->psz_demux, p_demux->psz_path );
61     }
62
63     p_demux->s          = s;
64     p_demux->out        = out;
65
66     p_demux->pf_demux   = NULL;
67     p_demux->pf_control = NULL;
68     p_demux->p_sys      = NULL;
69     p_demux->info.i_update = 0;
70     p_demux->info.i_title  = 0;
71     p_demux->info.i_seekpoint = 0;
72
73     if( s ) psz_module = p_demux->psz_demux;
74     else 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
80         *     anyway
81         *  - wav can't be added 'cause of a52 and dts in them as raw audio
82          */
83          static struct { char *ext; char *demux; } exttodemux[] =
84          {
85             { "aac",  "aac" },
86             { "aiff", "aiff" },
87             { "asf",  "asf" }, { "wmv",  "asf" }, { "wma",  "asf" },
88             { "avi",  "avi" },
89             { "au",   "au" },
90             { "flac", "flac" },
91             { "dv",   "dv" },
92             { "m3u",  "playlist" },
93             { "mkv",  "mkv" }, { "mka",  "mkv" }, { "mks",  "mkv" },
94             { "mp4",  "mp4" }, { "m4a",  "mp4" }, { "mov",  "mp4" }, { "moov", "mp4" },
95             { "mod",  "mod" }, { "xm",   "mod" },
96             { "nsv",  "nsv" },
97             { "ogg",  "ogg" }, { "ogm",  "ogg" },
98             { "pva",  "pva" },
99             { "rm",   "rm" },
100             { NULL,  NULL },
101         };
102         /* Here, we don't mind if it does not work, it must be quick */
103         static struct { char *ext; char *demux; } exttodemux_quick[] =
104         {
105             { "mp3", "mpga" },
106             { "ogg", "ogg" },
107             { "wma", "asf" },
108             { NULL, NULL }
109         };
110
111         char *psz_ext = strrchr( p_demux->psz_path, '.' ) + 1;
112         int  i;
113
114         if( !b_quick )
115         {
116             for( i = 0; exttodemux[i].ext != NULL; i++ )
117             {
118                 if( !strcasecmp( psz_ext, exttodemux[i].ext ) )
119                 {
120                     psz_module = exttodemux[i].demux;
121                     break;
122                 }
123             }
124         }
125         else
126         {
127             for( i = 0; exttodemux_quick[i].ext != NULL; i++ )
128             {
129                 if( !strcasecmp( psz_ext, exttodemux_quick[i].ext ) )
130                 {
131                     psz_module = exttodemux_quick[i].demux;
132                     break;
133                 }
134             }
135
136         }
137     }
138
139     /* Before module_Need (for var_Create...) */
140     vlc_object_attach( p_demux, p_obj );
141
142     if( s )
143     {
144         /* ID3 tags will mess-up demuxer probing so we skip it here.
145          * ID3 parsers will called later on in the demuxer to access the
146          * skipped info. */
147         SkipID3Tag( p_demux );
148
149         p_demux->p_module =
150             module_Need( p_demux, "demux2", psz_module,
151                          !strcmp( psz_module, p_demux->psz_demux ) ?
152                          VLC_TRUE : VLC_FALSE );
153     }
154     else
155     {
156         p_demux->p_module =
157             module_Need( p_demux, "access_demux", psz_module,
158                          !strcmp( psz_module, p_demux->psz_access ) ?
159                          VLC_TRUE : VLC_FALSE );
160     }
161
162     if( p_demux->p_module == NULL )
163     {
164         vlc_object_detach( p_demux );
165         free( p_demux->psz_path );
166         free( p_demux->psz_demux );
167         free( p_demux->psz_access );
168         vlc_object_destroy( p_demux );
169         return NULL;
170     }
171
172     return p_demux;
173 }
174
175 /*****************************************************************************
176  * demux2_Delete:
177  *****************************************************************************/
178 void demux2_Delete( demux_t *p_demux )
179 {
180     module_Unneed( p_demux, p_demux->p_module );
181     vlc_object_detach( p_demux );
182
183     free( p_demux->psz_path );
184     free( p_demux->psz_demux );
185     free( p_demux->psz_access );
186
187     vlc_object_destroy( p_demux );
188 }
189
190 /*****************************************************************************
191  * demux2_vaControlHelper:
192  *****************************************************************************/
193 int demux2_vaControlHelper( stream_t *s,
194                             int64_t i_start, int64_t i_end,
195                             int i_bitrate, int i_align,
196                             int i_query, va_list args )
197 {
198     int64_t i_tell;
199     double  f, *pf;
200     int64_t i64, *pi64;
201
202     if( i_end < 0 )    i_end   = stream_Size( s );
203     if( i_start < 0 )  i_start = 0;
204     if( i_align <= 0 ) i_align = 1;
205     i_tell = stream_Tell( s );
206
207     switch( i_query )
208     {
209         case DEMUX_GET_LENGTH:
210             pi64 = (int64_t*)va_arg( args, int64_t * );
211             if( i_bitrate > 0 && i_end > i_start )
212             {
213                 *pi64 = I64C(8000000) * (i_end - i_start) / i_bitrate;
214                 return VLC_SUCCESS;
215             }
216             return VLC_EGENERIC;
217
218         case DEMUX_GET_TIME:
219             pi64 = (int64_t*)va_arg( args, int64_t * );
220             if( i_bitrate > 0 && i_end > i_start )
221             {
222                 *pi64 = I64C(8000000) * (i_tell - i_start) / i_bitrate;
223                 return VLC_SUCCESS;
224             }
225             return VLC_EGENERIC;
226
227         case DEMUX_GET_POSITION:
228             pf = (double*)va_arg( args, double * );
229             if( i_start < i_end )
230             {
231                 *pf = (double)( i_tell - i_start ) /
232                       (double)( i_end  - i_start );
233                 return VLC_SUCCESS;
234             }
235             return VLC_EGENERIC;
236
237
238         case DEMUX_SET_POSITION:
239             f = (double)va_arg( args, double );
240             if( i_start < i_end && f >= 0.0 && f <= 1.0 )
241             {
242                 int64_t i_block = (f * ( i_end - i_start )) / i_align;
243
244                 if( stream_Seek( s, i_start + i_block * i_align ) )
245                 {
246                     return VLC_EGENERIC;
247                 }
248                 return VLC_SUCCESS;
249             }
250             return VLC_EGENERIC;
251
252         case DEMUX_SET_TIME:
253             i64 = (int64_t)va_arg( args, int64_t );
254             if( i_bitrate > 0 && i64 >= 0 )
255             {
256                 int64_t i_block = i64 * i_bitrate / I64C(8000000) / i_align;
257                 if( stream_Seek( s, i_start + i_block * i_align ) )
258                 {
259                     return VLC_EGENERIC;
260                 }
261                 return VLC_SUCCESS;
262             }
263             return VLC_EGENERIC;
264
265         case DEMUX_GET_FPS:
266         case DEMUX_GET_META:
267         case DEMUX_SET_NEXT_DEMUX_TIME:
268         case DEMUX_GET_TITLE_INFO:
269         case DEMUX_SET_GROUP:
270             return VLC_EGENERIC;
271
272         default:
273             msg_Err( s, "unknown query in demux_vaControlDefault" );
274             return VLC_EGENERIC;
275     }
276 }
277
278 /****************************************************************************
279  * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
280  ****************************************************************************/
281 typedef struct
282 {
283     /* Data buffer */
284     block_fifo_t *p_fifo;
285     block_t      *p_block;
286
287     int64_t     i_pos;
288
289     /* Demuxer */
290     char        *psz_name;
291     es_out_t    *out;
292     demux_t     *p_demux;
293
294 } d_stream_sys_t;
295
296 static int DStreamRead   ( stream_t *, void *p_read, int i_read );
297 static int DStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
298 static int DStreamControl( stream_t *, int i_query, va_list );
299 static int DStreamThread ( stream_t * );
300
301
302 stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux,
303                              es_out_t *out )
304 {
305     /* We create a stream reader, and launch a thread */
306     stream_t       *s;
307     d_stream_sys_t *p_sys;
308
309     if( psz_demux == NULL || *psz_demux == '\0' ) return NULL;
310
311     s = vlc_object_create( p_obj, VLC_OBJECT_STREAM );
312     s->pf_block  = NULL;
313     s->pf_read   = DStreamRead;
314     s->pf_peek   = DStreamPeek;
315     s->pf_control= DStreamControl;
316
317     s->i_char_width = 1;
318     s->b_little_endian = VLC_FALSE;
319
320     s->p_sys = malloc( sizeof( d_stream_sys_t) );
321     p_sys = (d_stream_sys_t*)s->p_sys;
322
323     p_sys->i_pos = 0;
324     p_sys->out = out;
325     p_sys->p_demux = NULL;
326     p_sys->p_block = NULL;
327     p_sys->psz_name = strdup( psz_demux );
328
329     /* decoder fifo */
330     if( ( p_sys->p_fifo = block_FifoNew( s ) ) == NULL )
331     {
332         msg_Err( s, "out of memory" );
333         vlc_object_destroy( s );
334         free( p_sys );
335         return NULL;
336     }
337
338     if( vlc_thread_create( s, "stream out", DStreamThread,
339                            VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
340     {
341         vlc_object_destroy( s );
342         free( p_sys );
343         return NULL;
344     }
345
346     return s;
347 }
348
349 void stream_DemuxSend( stream_t *s, block_t *p_block )
350 {
351     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
352     if( p_block ) block_FifoPut( p_sys->p_fifo, p_block );
353 }
354
355 void stream_DemuxDelete( stream_t *s )
356 {
357     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
358     block_t *p_empty;
359
360     s->b_die = VLC_TRUE;
361     if( p_sys->p_demux ) p_sys->p_demux->b_die = VLC_TRUE;
362     p_empty = block_New( s, 1 ); p_empty->i_buffer = 0;
363     block_FifoPut( p_sys->p_fifo, p_empty );
364     vlc_thread_join( s );
365
366     if( p_sys->p_demux ) demux2_Delete( p_sys->p_demux );
367     if( p_sys->p_block ) block_Release( p_sys->p_block );
368
369     block_FifoRelease( p_sys->p_fifo );
370     free( p_sys->psz_name );
371     free( p_sys );
372
373     vlc_object_destroy( s );
374 }
375
376
377 static int DStreamRead( stream_t *s, void *p_read, int i_read )
378 {
379     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
380     uint8_t *p_out = p_read;
381     int i_out = 0;
382
383     //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
384
385     while( !s->b_die && !s->b_error && i_read )
386     {
387         block_t *p_block = p_sys->p_block;
388         int i_copy;
389
390         if( !p_block )
391         {
392             p_block = block_FifoGet( p_sys->p_fifo );
393             if( !p_block ) s->b_error = 1;
394             p_sys->p_block = p_block;
395         }
396
397         if( p_block && i_read )
398         {
399             i_copy = __MIN( i_read, p_block->i_buffer );
400             if( p_out && i_copy ) memcpy( p_out, p_block->p_buffer, i_copy );
401             i_read -= i_copy;
402             i_out += i_copy;
403             p_block->i_buffer -= i_copy;
404             p_block->p_buffer += i_copy;
405
406             if( !p_block->i_buffer )
407             {
408                 block_Release( p_block );
409                 p_sys->p_block = NULL;
410             }
411         }
412     }
413
414     p_sys->i_pos += i_out;
415     return i_out;
416 }
417
418 static int DStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
419 {
420     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
421     block_t **pp_block = &p_sys->p_block;
422     int i_out = 0;
423     *pp_peek = 0;
424
425     //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
426
427     while( !s->b_die && !s->b_error && i_peek )
428     {
429         int i_copy;
430
431         if( !*pp_block )
432         {
433             *pp_block = block_FifoGet( p_sys->p_fifo );
434             if( !*pp_block ) s->b_error = 1;
435         }
436
437         if( *pp_block && i_peek )
438         {
439             i_copy = __MIN( i_peek, (*pp_block)->i_buffer );
440             i_peek -= i_copy;
441             i_out += i_copy;
442
443             if( i_peek ) pp_block = &(*pp_block)->p_next;
444         }
445     }
446
447     if( p_sys->p_block )
448     {
449         p_sys->p_block = block_ChainGather( p_sys->p_block );
450         *pp_peek = p_sys->p_block->p_buffer;
451     }
452
453     return i_out;
454 }
455
456 static int DStreamControl( stream_t *s, int i_query, va_list args )
457 {
458     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
459     int64_t    *p_i64;
460     vlc_bool_t *p_b;
461     int        *p_int;
462
463     switch( i_query )
464     {
465         case STREAM_GET_SIZE:
466             p_i64 = (int64_t*) va_arg( args, int64_t * );
467             *p_i64 = 0;
468             return VLC_SUCCESS;
469
470         case STREAM_CAN_SEEK:
471             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
472             *p_b = VLC_FALSE;
473             return VLC_SUCCESS;
474
475         case STREAM_CAN_FASTSEEK:
476             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
477             *p_b = VLC_FALSE;
478             return VLC_SUCCESS;
479
480         case STREAM_GET_POSITION:
481             p_i64 = (int64_t*) va_arg( args, int64_t * );
482             *p_i64 = p_sys->i_pos;
483             return VLC_SUCCESS;
484
485         case STREAM_SET_POSITION:
486         {
487             int64_t i64 = (int64_t)va_arg( args, int64_t );
488             int i_skip;
489             if( i64 < p_sys->i_pos ) return VLC_EGENERIC;
490             i_skip = i64 - p_sys->i_pos;
491
492             while( i_skip > 0 )
493             {
494                 int i_read = DStreamRead( s, NULL, i_skip );
495                 if( i_read <= 0 ) return VLC_EGENERIC;
496                 i_skip -= i_read;
497             }
498             return VLC_SUCCESS;
499         }
500
501         case STREAM_GET_MTU:
502             p_int = (int*) va_arg( args, int * );
503             *p_int = 0;
504             return VLC_SUCCESS;
505
506         case STREAM_CONTROL_ACCESS:
507             return VLC_EGENERIC;
508
509         default:
510             msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
511             return VLC_EGENERIC;
512     }
513 }
514
515 static int DStreamThread( stream_t *s )
516 {
517     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
518     demux_t *p_demux;
519
520     /* Create the demuxer */
521     if( !(p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out,
522                                VLC_FALSE )) )
523     {
524         return VLC_EGENERIC;
525     }
526
527     p_sys->p_demux = p_demux;
528
529     /* Main loop */
530     while( !s->b_die && !p_demux->b_die )
531     {
532         if( p_demux->pf_demux( p_demux ) <= 0 ) break;
533     }
534
535     p_demux->b_die = VLC_TRUE;
536     return VLC_SUCCESS;
537 }
538
539 /****************************************************************************
540  * Utility functions
541  ****************************************************************************/
542 static void SkipID3Tag( demux_t *p_demux )
543 {
544     uint8_t *p_peek;
545     uint8_t version, revision;
546     int i_size;
547     int b_footer;
548
549     if( !p_demux->s ) return;
550
551     /* Get 10 byte id3 header */
552     if( stream_Peek( p_demux->s, &p_peek, 10 ) < 10 ) return;
553
554     if( p_peek[0] != 'I' || p_peek[1] != 'D' || p_peek[2] != '3' ) return;
555
556     version = p_peek[3];
557     revision = p_peek[4];
558     b_footer = p_peek[5] & 0x10;
559     i_size = (p_peek[6]<<21) + (p_peek[7]<<14) + (p_peek[8]<<7) + p_peek[9];
560
561     if( b_footer ) i_size += 10;
562     i_size += 10;
563
564     /* Skip the entire tag */
565     stream_Read( p_demux->s, NULL, i_size );
566
567     msg_Dbg( p_demux, "ID3v2.%d revision %d tag found, skiping %d bytes",
568              version, revision, i_size );
569
570     return;
571 }