]> git.sesse.net Git - vlc/blob - src/input/demux.c
9cc6bebdbef35704362ae59dc1ca6ad3e416f0f4
[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             { NULL,  NULL },
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 ) ?
123                          VLC_TRUE : VLC_FALSE );
124     }
125     else
126     {
127         p_demux->p_module =
128             module_Need( p_demux, "access_demux", psz_module,
129                          !strcmp( psz_module, p_demux->psz_access ) ?
130                          VLC_TRUE : VLC_FALSE );
131     }
132
133     if( p_demux->p_module == NULL )
134     {
135         vlc_object_detach( p_demux );
136         free( p_demux->psz_path );
137         free( p_demux->psz_demux );
138         free( p_demux->psz_access );
139         vlc_object_destroy( p_demux );
140         return NULL;
141     }
142
143     return p_demux;
144 }
145
146 /*****************************************************************************
147  * demux2_Delete:
148  *****************************************************************************/
149 void demux2_Delete( demux_t *p_demux )
150 {
151     module_Unneed( p_demux, p_demux->p_module );
152     vlc_object_detach( p_demux );
153
154     free( p_demux->psz_path );
155     free( p_demux->psz_demux );
156     free( p_demux->psz_access );
157
158     vlc_object_destroy( p_demux );
159 }
160
161 /*****************************************************************************
162  * demux2_vaControlHelper:
163  *****************************************************************************/
164 int demux2_vaControlHelper( stream_t *s,
165                             int64_t i_start, int64_t i_end,
166                             int i_bitrate, int i_align,
167                             int i_query, va_list args )
168 {
169     int64_t i_tell;
170     double  f, *pf;
171     int64_t i64, *pi64;
172
173     if( i_end < 0 )    i_end   = stream_Size( s );
174     if( i_start < 0 )  i_start = 0;
175     if( i_align <= 0 ) i_align = 1;
176     i_tell = stream_Tell( s );
177
178     switch( i_query )
179     {
180         case DEMUX_GET_LENGTH:
181             pi64 = (int64_t*)va_arg( args, int64_t * );
182             if( i_bitrate > 0 && i_end > i_start )
183             {
184                 *pi64 = I64C(8000000) * (i_end - i_start) / i_bitrate;
185                 return VLC_SUCCESS;
186             }
187             return VLC_EGENERIC;
188
189         case DEMUX_GET_TIME:
190             pi64 = (int64_t*)va_arg( args, int64_t * );
191             if( i_bitrate > 0 && i_end > i_start )
192             {
193                 *pi64 = I64C(8000000) * (i_tell - i_start) / i_bitrate;
194                 return VLC_SUCCESS;
195             }
196             return VLC_EGENERIC;
197
198         case DEMUX_GET_POSITION:
199             pf = (double*)va_arg( args, double * );
200             if( i_start < i_end )
201             {
202                 *pf = (double)( i_tell - i_start ) /
203                       (double)( i_end  - i_start );
204                 return VLC_SUCCESS;
205             }
206             return VLC_EGENERIC;
207
208
209         case DEMUX_SET_POSITION:
210             f = (double)va_arg( args, double );
211             if( i_start < i_end && f >= 0.0 && f <= 1.0 )
212             {
213                 int64_t i_block = (f * ( i_end - i_start )) / i_align;
214
215                 if( stream_Seek( s, i_start + i_block * i_align ) )
216                 {
217                     return VLC_EGENERIC;
218                 }
219                 return VLC_SUCCESS;
220             }
221             return VLC_EGENERIC;
222
223         case DEMUX_SET_TIME:
224             i64 = (int64_t)va_arg( args, int64_t );
225             if( i_bitrate > 0 && i64 >= 0 )
226             {
227                 int64_t i_block = i64 * i_bitrate / I64C(8000000) / i_align;
228                 if( stream_Seek( s, i_start + i_block * i_align ) )
229                 {
230                     return VLC_EGENERIC;
231                 }
232                 return VLC_SUCCESS;
233             }
234             return VLC_EGENERIC;
235
236         case DEMUX_GET_FPS:
237         case DEMUX_GET_META:
238         case DEMUX_SET_NEXT_DEMUX_TIME:
239         case DEMUX_GET_TITLE_INFO:
240         case DEMUX_SET_GROUP:
241             return VLC_EGENERIC;
242
243         default:
244             msg_Err( s, "unknown query in demux_vaControlDefault" );
245             return VLC_EGENERIC;
246     }
247 }
248
249 /****************************************************************************
250  * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
251  ****************************************************************************/
252 typedef struct
253 {
254     /* Data buffer */
255     block_fifo_t *p_fifo;
256     block_t      *p_block;
257
258     int64_t     i_pos;
259
260     /* Demuxer */
261     char        *psz_name;
262     es_out_t    *out;
263     demux_t     *p_demux;
264
265 } d_stream_sys_t;
266
267 static int DStreamRead   ( stream_t *, void *p_read, int i_read );
268 static int DStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
269 static int DStreamControl( stream_t *, int i_query, va_list );
270 static int DStreamThread ( stream_t * );
271
272
273 stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux,
274                              es_out_t *out )
275 {
276     /* We create a stream reader, and launch a thread */
277     stream_t       *s;
278     d_stream_sys_t *p_sys;
279
280     if( psz_demux == NULL || *psz_demux == '\0' ) return NULL;
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     p_sys->i_pos = 0;
292     p_sys->out = out;
293     p_sys->p_demux = NULL;
294     p_sys->p_block = NULL;
295     p_sys->psz_name = strdup( psz_demux );
296
297     /* decoder fifo */
298     if( ( p_sys->p_fifo = block_FifoNew( s ) ) == NULL )
299     {
300         msg_Err( s, "out of memory" );
301         vlc_object_destroy( s );
302         free( p_sys );
303         return NULL;
304     }
305
306     if( vlc_thread_create( s, "stream out", DStreamThread,
307                            VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
308     {
309         vlc_object_destroy( s );
310         free( p_sys );
311         return NULL;
312     }
313
314     return s;
315 }
316
317 void stream_DemuxSend( stream_t *s, block_t *p_block )
318 {
319     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
320     if( p_block ) block_FifoPut( p_sys->p_fifo, p_block );
321 }
322
323 void stream_DemuxDelete( stream_t *s )
324 {
325     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
326     block_t *p_empty;
327
328     s->b_die = VLC_TRUE;
329     if( p_sys->p_demux ) p_sys->p_demux->b_die = VLC_TRUE;
330     p_empty = block_New( s, 1 ); p_empty->i_buffer = 0;
331     block_FifoPut( p_sys->p_fifo, p_empty );
332     vlc_thread_join( s );
333
334     if( p_sys->p_demux ) demux2_Delete( p_sys->p_demux );
335     if( p_sys->p_block ) block_Release( p_sys->p_block );
336
337     block_FifoRelease( p_sys->p_fifo );
338     free( p_sys->psz_name );
339     free( p_sys );
340
341     vlc_object_destroy( s );
342 }
343
344
345 static int DStreamRead( stream_t *s, void *p_read, int i_read )
346 {
347     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
348     uint8_t *p_out = p_read;
349     int i_out = 0;
350
351     //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
352
353     while( !s->b_die && !s->b_error && i_read )
354     {
355         block_t *p_block = p_sys->p_block;
356         int i_copy;
357
358         if( !p_block )
359         {
360             p_block = block_FifoGet( p_sys->p_fifo );
361             if( !p_block ) s->b_error = 1;
362             p_sys->p_block = p_block;
363         }
364
365         if( p_block && i_read )
366         {
367             i_copy = __MIN( i_read, p_block->i_buffer );
368             if( p_out && i_copy ) memcpy( p_out, p_block->p_buffer, i_copy );
369             i_read -= i_copy;
370             i_out += i_copy;
371             p_block->i_buffer -= i_copy;
372             p_block->p_buffer += i_copy;
373
374             if( !p_block->i_buffer )
375             {
376                 block_Release( p_block );
377                 p_sys->p_block = NULL;
378             }
379         }
380     }
381
382     p_sys->i_pos += i_out;
383     return i_out;
384 }
385
386 static int DStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
387 {
388     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
389     block_t **pp_block = &p_sys->p_block;
390     int i_out = 0;
391     *pp_peek = 0;
392
393     //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
394
395     while( !s->b_die && !s->b_error && i_peek )
396     {
397         int i_copy;
398
399         if( !*pp_block )
400         {
401             *pp_block = block_FifoGet( p_sys->p_fifo );
402             if( !*pp_block ) s->b_error = 1;
403         }
404
405         if( *pp_block && i_peek )
406         {
407             i_copy = __MIN( i_peek, (*pp_block)->i_buffer );
408             i_peek -= i_copy;
409             i_out += i_copy;
410
411             if( i_peek ) pp_block = &(*pp_block)->p_next;
412         }
413     }
414
415     if( p_sys->p_block )
416     {
417         p_sys->p_block = block_ChainGather( p_sys->p_block );
418         *pp_peek = p_sys->p_block->p_buffer;
419     }
420
421     return i_out;
422 }
423
424 static int DStreamControl( stream_t *s, int i_query, va_list args )
425 {
426     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
427     int64_t    *p_i64;
428     vlc_bool_t *p_b;
429     int        *p_int;
430
431     switch( i_query )
432     {
433         case STREAM_GET_SIZE:
434             p_i64 = (int64_t*) va_arg( args, int64_t * );
435             *p_i64 = 0;
436             return VLC_SUCCESS;
437
438         case STREAM_CAN_SEEK:
439             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
440             *p_b = VLC_FALSE;
441             return VLC_SUCCESS;
442
443         case STREAM_CAN_FASTSEEK:
444             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
445             *p_b = VLC_FALSE;
446             return VLC_SUCCESS;
447
448         case STREAM_GET_POSITION:
449             p_i64 = (int64_t*) va_arg( args, int64_t * );
450             *p_i64 = p_sys->i_pos;
451             return VLC_SUCCESS;
452
453         case STREAM_SET_POSITION:
454         {
455             int64_t i64 = (int64_t)va_arg( args, int64_t );
456             int i_skip;
457             if( i64 < p_sys->i_pos ) return VLC_EGENERIC;
458             i_skip = i64 - p_sys->i_pos;
459
460             while( i_skip > 0 )
461             {
462                 int i_read = DStreamRead( s, NULL, i_skip );
463                 if( i_read <= 0 ) return VLC_EGENERIC;
464                 i_skip -= i_read;
465             }
466             return VLC_SUCCESS;
467         }
468
469         case STREAM_GET_MTU:
470             p_int = (int*) va_arg( args, int * );
471             *p_int = 0;
472             return VLC_SUCCESS;
473
474         case STREAM_CONTROL_ACCESS:
475             return VLC_EGENERIC;
476
477         default:
478             msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
479             return VLC_EGENERIC;
480     }
481 }
482
483 static int DStreamThread( stream_t *s )
484 {
485     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
486     demux_t *p_demux;
487
488     /* Create the demuxer */
489     if( !(p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out )) )
490     {
491         return VLC_EGENERIC;
492     }
493
494     p_sys->p_demux = p_demux;
495
496     /* Main loop */
497     while( !s->b_die && !p_demux->b_die )
498     {
499         if( p_demux->pf_demux( p_demux ) <= 0 ) break;
500     }
501
502     p_demux->b_die = VLC_TRUE;
503     return VLC_SUCCESS;
504 }