input/demux: remove legacy comment that is no longer relevant
[vlc.git] / src / input / demux.c
1 /*****************************************************************************
2  * demux.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VLC authors and 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 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
28 #include <assert.h>
29
30 #include "demux.h"
31 #include <libvlc.h>
32 #include <vlc_codec.h>
33 #include <vlc_meta.h>
34 #include <vlc_url.h>
35 #include <vlc_modules.h>
36 #include <vlc_strings.h>
37
38 static bool SkipID3Tag( demux_t * );
39 static bool SkipAPETag( demux_t *p_demux );
40
41 typedef const struct
42 {
43     const char* key;
44     const char* name;
45
46 } demux_mapping;
47
48 static int demux_mapping_cmp( const void *k, const void *v )
49 {
50     demux_mapping* entry = v;
51     return vlc_ascii_strcasecmp( k, entry->key );
52 }
53
54 static demux_mapping* demux_lookup( char const* key,
55                                     demux_mapping* data, size_t size )
56 {
57     return bsearch( key, data, size, sizeof( *data ), demux_mapping_cmp );
58 }
59
60 static const char *demux_NameFromContentType(const char *mime)
61 {
62     static demux_mapping types[] =
63     {   /* Must be sorted in ascending ASCII order */
64         { "audio/aac",           "m4a"     },
65         { "audio/aacp",          "m4a"     },
66         { "audio/mpeg",          "mp3"     },
67         { "application/rss+xml", "podcast" },
68         //{ "video/MP1S",          "es,mpgv" }, !b_force
69         { "video/dv",            "rawdv"   },
70         { "video/MP2P",          "ps"      },
71         { "video/MP2T",          "ts"      },
72         { "video/nsa",           "nsv"     },
73         { "video/nsv",           "nsv"     },
74     };
75     demux_mapping *type = demux_lookup( mime, types, ARRAY_SIZE( types ) );
76     return (type != NULL) ? type->name : "any";
77 }
78
79 static const char* DemuxNameFromExtension( char const* ext,
80                                            bool b_preparsing )
81 {
82     /* NOTE: Add only file without any problems here and with strong detection:
83      * - no .mp3, .a52, ...
84      *  - wav can't be added 'cause of a52 and dts in them as raw audio
85      */
86     static demux_mapping strong[] =
87     { /* NOTE: must be sorted in asc order */
88         { "aiff", "aiff" },
89         { "asf",  "asf" },
90         { "au",   "au" },
91         { "avi",  "avi" },
92         { "drc",  "dirac" },
93         { "dv",   "dv" },
94         { "flac", "flac" },
95         { "h264", "h264" },
96         { "kar", "smf" },
97         { "m3u",  "m3u" },
98         { "m4a",  "mp4" },
99         { "m4v",  "m4v" },
100         { "mid",  "smf" },
101         { "mka",  "mkv" },
102         { "mks",  "mkv" },
103         { "mkv",  "mkv" },
104         { "moov", "mp4" },
105         { "mov",  "mp4" },
106         { "mp4",  "mp4" },
107         { "nsv",  "nsv" },
108         { "oga",  "ogg" },
109         { "ogg",  "ogg" },
110         { "ogm",  "ogg" },
111         { "ogv",  "ogg" },
112         { "ogx",  "ogg" }, /*RFC5334*/
113         { "opus", "ogg" }, /*draft-terriberry-oggopus-01*/
114         { "pva",  "pva" },
115         { "rm",   "avformat" },
116         { "rmi",  "smf" },
117         { "spx",  "ogg" },
118         { "voc",  "voc" },
119         { "wma",  "asf" },
120         { "wmv",  "asf" },
121     };
122
123     /* Here, we don't mind if it does not work, it must be quick */
124     static demux_mapping quick[] =
125     { /* NOTE: shall be sorted in asc order */
126         { "mp3", "mpga" },
127         { "ogg", "ogg" },
128         { "wma", "asf" },
129     };
130
131     struct {
132         demux_mapping* data;
133         size_t size;
134
135     } lookup = {
136         .data = b_preparsing ? quick : strong,
137         .size = b_preparsing ? ARRAY_SIZE( quick ) : ARRAY_SIZE( strong )
138     };
139
140     demux_mapping* result = demux_lookup( ext, lookup.data, lookup.size );
141     return result ? result->name : NULL;
142 }
143
144 /*****************************************************************************
145  * demux_New:
146  *  if s is NULL then load a access_demux
147  *****************************************************************************/
148 demux_t *demux_New( vlc_object_t *p_obj, const char *psz_name,
149                     const char *psz_location, stream_t *s, es_out_t *out )
150 {
151     return demux_NewAdvanced( p_obj, NULL,
152                               (s == NULL) ? psz_name : "",
153                               (s != NULL) ? psz_name : "",
154                               psz_location, s, out, false );
155 }
156
157 typedef struct demux_priv_t
158 {
159     demux_t demux;
160     void (*destroy)(demux_t *);
161 } demux_priv_t;
162
163 static void demux_DestroyDemux(demux_t *demux)
164 {
165     assert(demux->s != NULL);
166     vlc_stream_Delete(demux->s);
167 }
168
169 static void demux_DestroyAccessDemux(demux_t *demux)
170 {
171     assert(demux->s == NULL);
172     (void) demux;
173 }
174
175 static void demux_DestroyDemuxFilter(demux_t *demux)
176 {
177     assert(demux->p_next != NULL);
178     (void) demux;
179 }
180
181 /*****************************************************************************
182  * demux_NewAdvanced:
183  *  if s is NULL then load a access_demux
184  *****************************************************************************/
185 #undef demux_NewAdvanced
186 demux_t *demux_NewAdvanced( vlc_object_t *p_obj, input_thread_t *p_parent_input,
187                             const char *psz_access, const char *psz_demux,
188                             const char *psz_location,
189                             stream_t *s, es_out_t *out, bool b_preparsing )
190 {
191     demux_priv_t *priv = vlc_custom_create(p_obj, sizeof (*priv), "demux");
192     if (unlikely(priv == NULL))
193         return NULL;
194
195     demux_t *p_demux = &priv->demux;
196
197     if( s != NULL && (!strcasecmp( psz_demux, "any" ) || !psz_demux[0]) )
198     {   /* Look up demux by Content-Type for hard to detect formats */
199         char *type = stream_ContentType( s );
200         if( type != NULL )
201         {
202             psz_demux = demux_NameFromContentType( type );
203             free( type );
204         }
205     }
206
207     p_demux->p_input = p_parent_input;
208     p_demux->psz_access = strdup( psz_access );
209     p_demux->psz_demux = strdup( psz_demux );
210     p_demux->psz_location = strdup( psz_location );
211     p_demux->psz_file = get_path( psz_location ); /* parse URL */
212
213     if( unlikely(p_demux->psz_access == NULL
214               || p_demux->psz_demux == NULL
215               || p_demux->psz_location == NULL) )
216         goto error;
217
218     if( !b_preparsing )
219         msg_Dbg( p_obj, "creating demux: access='%s' demux='%s' "
220                  "location='%s' file='%s'",
221                  p_demux->psz_access, p_demux->psz_demux,
222                  p_demux->psz_location, p_demux->psz_file );
223
224     p_demux->s              = s;
225     p_demux->out            = out;
226     p_demux->b_preparsing   = b_preparsing;
227
228     p_demux->pf_demux   = NULL;
229     p_demux->pf_control = NULL;
230     p_demux->p_sys      = NULL;
231     p_demux->info.i_update = 0;
232     p_demux->info.i_title  = 0;
233     p_demux->info.i_seekpoint = 0;
234     priv->destroy = s ? demux_DestroyDemux : demux_DestroyAccessDemux;
235
236     if( s != NULL )
237     {
238         const char *psz_module = NULL;
239
240         if( !strcmp( p_demux->psz_demux, "any" ) && p_demux->psz_file )
241         {
242             char const* psz_ext = strrchr( p_demux->psz_file, '.' );
243
244             if( psz_ext )
245                 psz_module = DemuxNameFromExtension( psz_ext + 1, b_preparsing );
246         }
247
248         if( psz_module == NULL )
249             psz_module = p_demux->psz_demux;
250
251         /* ID3/APE tags will mess-up demuxer probing so we skip it here.
252          * ID3/APE parsers will called later on in the demuxer to access the
253          * skipped info. */
254         while (SkipID3Tag( p_demux ))
255           ;
256         SkipAPETag( p_demux );
257
258         p_demux->p_module =
259             module_need( p_demux, "demux", psz_module,
260                          !strcmp( psz_module, p_demux->psz_demux ) );
261     }
262     else
263     {
264         p_demux->p_module =
265             module_need( p_demux, "access_demux", p_demux->psz_access, true );
266     }
267
268     if( p_demux->p_module == NULL )
269         goto error;
270
271     return p_demux;
272 error:
273     free( p_demux->psz_file );
274     free( p_demux->psz_location );
275     free( p_demux->psz_demux );
276     free( p_demux->psz_access );
277     vlc_object_release( p_demux );
278     return NULL;
279 }
280
281 demux_t *input_DemuxNew( vlc_object_t *obj, const char *access_name,
282                          const char *demux_name, const char *path,
283                          es_out_t *out, bool preparsing, input_thread_t *input )
284 {
285     char *demux_var = NULL;
286
287     assert( access_name != NULL );
288     assert( demux_name != NULL );
289     assert( path != NULL );
290
291     if( demux_name[0] == '\0' )
292     {
293         demux_var = var_InheritString( obj, "demux" );
294         if( demux_var != NULL )
295         {
296             demux_name = demux_var;
297             msg_Dbg( obj, "specified demux: %s", demux_name );
298         }
299         else
300             demux_name = "any";
301     }
302
303     demux_t *demux = NULL;
304
305     if( preparsing )
306     {
307         if( strcasecmp( demux_name, "any" ) )
308             goto out;
309
310         msg_Dbg( obj, "preparsing %s://%s", access_name, path );
311     }
312     else /* Try access_demux first */
313         demux = demux_NewAdvanced( obj, input, access_name, demux_name, path,
314                                    NULL, out, false );
315
316     if( demux == NULL )
317     {   /* Then try a real access,stream,demux chain */
318         /* Create the stream_t */
319         stream_t *stream = NULL;
320         char *url;
321
322         if( likely(asprintf( &url, "%s://%s", access_name, path) >= 0) )
323         {
324             stream = stream_AccessNew( obj, input, preparsing, url );
325             free( url );
326         }
327
328         if( stream == NULL )
329         {
330             msg_Err( obj, "cannot access %s://%s", access_name, path );
331             goto out;
332         }
333
334         /* Add stream filters */
335         stream = stream_FilterAutoNew( stream );
336
337         char *filters = var_InheritString( obj, "stream-filter" );
338         if( filters != NULL )
339         {
340             stream = stream_FilterChainNew( stream, filters );
341             free( filters );
342         }
343
344         if( var_InheritBool( obj, "input-record-native" ) )
345             stream = stream_FilterChainNew( stream, "record" );
346
347         /* FIXME: Hysterical raisins. Access is not updated according to any
348          * redirect but path is. This does not make much sense. Probably the
349          * URL should be passed as a whole and demux_t.psz_access removed. */
350         if( stream->psz_url != NULL )
351         {
352             path = strstr( stream->psz_url, "://" );
353             if( path == NULL )
354             {
355                 vlc_stream_Delete( stream );
356                 goto out;
357             }
358             path += 3;
359         }
360
361         demux = demux_NewAdvanced( obj, input, access_name, demux_name, path,
362                                    stream, out, preparsing );
363         if( demux == NULL )
364         {
365             msg_Err( obj, "cannot parse %s://%s", access_name, path );
366             vlc_stream_Delete( stream );
367         }
368     }
369 out:
370     free( demux_var );
371     return demux;
372 }
373
374 /*****************************************************************************
375  * demux_Delete:
376  *****************************************************************************/
377 void demux_Delete( demux_t *p_demux )
378 {
379     demux_priv_t *priv = (demux_priv_t *)p_demux;
380
381     module_unneed( p_demux, p_demux->p_module );
382
383     priv->destroy(p_demux);
384     free( p_demux->psz_file );
385     free( p_demux->psz_location );
386     free( p_demux->psz_demux );
387     free( p_demux->psz_access );
388     vlc_object_release( p_demux );
389 }
390
391 #define static_control_match(foo) \
392     static_assert((unsigned) DEMUX_##foo == STREAM_##foo, "Mismatch")
393
394 static int demux_ControlInternal( demux_t *demux, int query, ... )
395 {
396     int ret;
397     va_list ap;
398
399     va_start( ap, query );
400     ret = demux->pf_control( demux, query, ap );
401     va_end( ap );
402     return ret;
403 }
404
405 int demux_vaControl( demux_t *demux, int query, va_list args )
406 {
407     if( demux->s != NULL )
408         switch( query )
409         {
410             /* Legacy fallback for missing getters in synchronous demuxers */
411             case DEMUX_CAN_PAUSE:
412             case DEMUX_CAN_CONTROL_PACE:
413             case DEMUX_GET_PTS_DELAY:
414             {
415                 int ret;
416                 va_list ap;
417
418                 va_copy( ap, args );
419                 ret = demux->pf_control( demux, query, args );
420                 if( ret != VLC_SUCCESS )
421                     ret = vlc_stream_vaControl( demux->s, query, ap );
422                 va_end( ap );
423                 return ret;
424             }
425
426             /* Some demuxers need to control pause directly (e.g. adaptive),
427              * but many legacy demuxers do not understand pause at all.
428              * If DEMUX_CAN_PAUSE is not implemented, bypass the demuxer and
429              * byte stream. If DEMUX_CAN_PAUSE is implemented and pause is
430              * supported, pause the demuxer normally. Else, something went very
431              * wrong.
432              *
433              * Note that this requires asynchronous/threaded demuxers to
434              * always return VLC_SUCCESS for DEMUX_CAN_PAUSE, so that they are
435              * never bypassed. Otherwise, we would reenter demux->s callbacks
436              * and break thread safety. At the time of writing, asynchronous or
437              * threaded *non-access* demuxers do not exist and are not fully
438              * supported by the input thread, so this is theoretical. */
439             case DEMUX_SET_PAUSE_STATE:
440             {
441                 bool can_pause;
442
443                 if( demux_ControlInternal( demux, DEMUX_CAN_PAUSE,
444                                            &can_pause ) )
445                     return vlc_stream_vaControl( demux->s, query, args );
446
447                 /* The caller shall not pause if pause is unsupported. */
448                 assert( can_pause );
449                 break;
450             }
451         }
452
453     return demux->pf_control( demux, query, args );
454 }
455
456 /*****************************************************************************
457  * demux_vaControlHelper:
458  *****************************************************************************/
459 int demux_vaControlHelper( stream_t *s,
460                             int64_t i_start, int64_t i_end,
461                             int64_t i_bitrate, int i_align,
462                             int i_query, va_list args )
463 {
464     int64_t i_tell;
465     double  f, *pf;
466     int64_t i64, *pi64;
467
468     if( i_end < 0 )    i_end   = stream_Size( s );
469     if( i_start < 0 )  i_start = 0;
470     if( i_align <= 0 ) i_align = 1;
471     i_tell = vlc_stream_Tell( s );
472
473     static_control_match(CAN_PAUSE);
474     static_control_match(CAN_CONTROL_PACE);
475     static_control_match(GET_PTS_DELAY);
476     static_control_match(GET_META);
477     static_control_match(GET_SIGNAL);
478     static_control_match(SET_PAUSE_STATE);
479
480     switch( i_query )
481     {
482         case DEMUX_CAN_SEEK:
483         {
484             bool *b = va_arg( args, bool * );
485
486             if( (i_bitrate <= 0 && i_start >= i_end)
487              || vlc_stream_Control( s, STREAM_CAN_SEEK, b ) )
488                 *b = false;
489             break;
490         }
491
492         case DEMUX_CAN_PAUSE:
493         case DEMUX_CAN_CONTROL_PACE:
494         case DEMUX_GET_PTS_DELAY:
495         case DEMUX_GET_META:
496         case DEMUX_GET_SIGNAL:
497         case DEMUX_SET_PAUSE_STATE:
498             return vlc_stream_vaControl( s, i_query, args );
499
500         case DEMUX_GET_LENGTH:
501             pi64 = (int64_t*)va_arg( args, int64_t * );
502             if( i_bitrate > 0 && i_end > i_start )
503             {
504                 *pi64 = INT64_C(8000000) * (i_end - i_start) / i_bitrate;
505                 return VLC_SUCCESS;
506             }
507             return VLC_EGENERIC;
508
509         case DEMUX_GET_TIME:
510             pi64 = (int64_t*)va_arg( args, int64_t * );
511             if( i_bitrate > 0 && i_tell >= i_start )
512             {
513                 *pi64 = INT64_C(8000000) * (i_tell - i_start) / i_bitrate;
514                 return VLC_SUCCESS;
515             }
516             return VLC_EGENERIC;
517
518         case DEMUX_GET_POSITION:
519             pf = (double*)va_arg( args, double * );
520             if( i_start < i_end )
521             {
522                 *pf = (double)( i_tell - i_start ) /
523                       (double)( i_end  - i_start );
524                 return VLC_SUCCESS;
525             }
526             return VLC_EGENERIC;
527
528
529         case DEMUX_SET_POSITION:
530             f = (double)va_arg( args, double );
531             if( i_start < i_end && f >= 0.0 && f <= 1.0 )
532             {
533                 int64_t i_block = (f * ( i_end - i_start )) / i_align;
534
535                 if( vlc_stream_Seek( s, i_start + i_block * i_align ) )
536                 {
537                     return VLC_EGENERIC;
538                 }
539                 return VLC_SUCCESS;
540             }
541             return VLC_EGENERIC;
542
543         case DEMUX_SET_TIME:
544             i64 = (int64_t)va_arg( args, int64_t );
545             if( i_bitrate > 0 && i64 >= 0 )
546             {
547                 int64_t i_block = i64 * i_bitrate / INT64_C(8000000) / i_align;
548                 if( vlc_stream_Seek( s, i_start + i_block * i_align ) )
549                 {
550                     return VLC_EGENERIC;
551                 }
552                 return VLC_SUCCESS;
553             }
554             return VLC_EGENERIC;
555
556         case DEMUX_IS_PLAYLIST:
557             *va_arg( args, bool * ) = false;
558             return VLC_SUCCESS;
559
560         case DEMUX_GET_FPS:
561         case DEMUX_HAS_UNSUPPORTED_META:
562         case DEMUX_SET_NEXT_DEMUX_TIME:
563         case DEMUX_GET_TITLE_INFO:
564         case DEMUX_SET_GROUP:
565         case DEMUX_SET_ES:
566         case DEMUX_GET_ATTACHMENTS:
567         case DEMUX_CAN_RECORD:
568         case DEMUX_TEST_AND_CLEAR_FLAGS:
569         case DEMUX_GET_TITLE:
570         case DEMUX_GET_SEEKPOINT:
571             return VLC_EGENERIC;
572
573         case DEMUX_SET_TITLE:
574         case DEMUX_SET_SEEKPOINT:
575         case DEMUX_SET_RECORD_STATE:
576             assert(0);
577         default:
578             msg_Err( s, "unknown query 0x%x in %s", i_query, __func__ );
579             return VLC_EGENERIC;
580     }
581     return VLC_SUCCESS;
582 }
583
584 /****************************************************************************
585  * Utility functions
586  ****************************************************************************/
587 decoder_t *demux_PacketizerNew( demux_t *p_demux, es_format_t *p_fmt, const char *psz_msg )
588 {
589     decoder_t *p_packetizer;
590     p_packetizer = vlc_custom_create( p_demux, sizeof( *p_packetizer ),
591                                       "demux packetizer" );
592     if( !p_packetizer )
593     {
594         es_format_Clean( p_fmt );
595         return NULL;
596     }
597     p_fmt->b_packetized = false;
598
599     p_packetizer->pf_decode_audio = NULL;
600     p_packetizer->pf_decode_video = NULL;
601     p_packetizer->pf_decode_sub = NULL;
602     p_packetizer->pf_packetize = NULL;
603
604     p_packetizer->fmt_in = *p_fmt;
605     es_format_Init( &p_packetizer->fmt_out, UNKNOWN_ES, 0 );
606
607     p_packetizer->p_module = module_need( p_packetizer, "packetizer", NULL, false );
608     if( !p_packetizer->p_module )
609     {
610         es_format_Clean( p_fmt );
611         vlc_object_release( p_packetizer );
612         msg_Err( p_demux, "cannot find packetizer for %s", psz_msg );
613         return NULL;
614     }
615
616     return p_packetizer;
617 }
618
619 void demux_PacketizerDestroy( decoder_t *p_packetizer )
620 {
621     if( p_packetizer->p_module )
622         module_unneed( p_packetizer, p_packetizer->p_module );
623     es_format_Clean( &p_packetizer->fmt_in );
624     es_format_Clean( &p_packetizer->fmt_out );
625     if( p_packetizer->p_description )
626         vlc_meta_Delete( p_packetizer->p_description );
627     vlc_object_release( p_packetizer );
628 }
629
630 static bool SkipID3Tag( demux_t *p_demux )
631 {
632     const uint8_t *p_peek;
633     uint8_t version, revision;
634     int i_size;
635     int b_footer;
636
637     if( !p_demux->s )
638         return false;
639
640     /* Get 10 byte id3 header */
641     if( vlc_stream_Peek( p_demux->s, &p_peek, 10 ) < 10 )
642         return false;
643
644     if( memcmp( p_peek, "ID3", 3 ) )
645         return false;
646
647     version = p_peek[3];
648     revision = p_peek[4];
649     b_footer = p_peek[5] & 0x10;
650     i_size = (p_peek[6]<<21) + (p_peek[7]<<14) + (p_peek[8]<<7) + p_peek[9];
651
652     if( b_footer ) i_size += 10;
653     i_size += 10;
654
655     /* Skip the entire tag */
656     if( vlc_stream_Read( p_demux->s, NULL, i_size ) < i_size )
657         return false;
658
659     msg_Dbg( p_demux, "ID3v2.%d revision %d tag found, skipping %d bytes",
660              version, revision, i_size );
661     return true;
662 }
663 static bool SkipAPETag( demux_t *p_demux )
664 {
665     const uint8_t *p_peek;
666     int i_version;
667     int i_size;
668     uint32_t flags;
669
670     if( !p_demux->s )
671         return false;
672
673     /* Get 32 byte ape header */
674     if( vlc_stream_Peek( p_demux->s, &p_peek, 32 ) < 32 )
675         return false;
676
677     if( memcmp( p_peek, "APETAGEX", 8 ) )
678         return false;
679
680     i_version = GetDWLE( &p_peek[8] );
681     flags = GetDWLE( &p_peek[8+4+4] );
682     if( ( i_version != 1000 && i_version != 2000 ) || !( flags & (1<<29) ) )
683         return false;
684
685     i_size = GetDWLE( &p_peek[8+4] ) + ( (flags&(1<<30)) ? 32 : 0 );
686
687     /* Skip the entire tag */
688     if( vlc_stream_Read( p_demux->s, NULL, i_size ) < i_size )
689         return false;
690
691     msg_Dbg( p_demux, "AP2 v%d tag found, skipping %d bytes",
692              i_version/1000, i_size );
693     return true;
694 }
695
696 unsigned demux_TestAndClearFlags( demux_t *p_demux, unsigned flags )
697 {
698     unsigned i_update;
699     if ( demux_Control( p_demux, DEMUX_TEST_AND_CLEAR_FLAGS, &i_update ) == VLC_SUCCESS )
700         return i_update;
701     unsigned ret = p_demux->info.i_update & flags;
702     p_demux->info.i_update &= ~flags;
703     return ret;
704 }
705
706 int demux_GetTitle( demux_t *p_demux )
707 {
708     int i_title;
709     if ( demux_Control( p_demux, DEMUX_GET_TITLE, &i_title ) == VLC_SUCCESS )
710         return i_title;
711     return p_demux->info.i_title;
712 }
713
714 int demux_GetSeekpoint( demux_t *p_demux )
715 {
716     int i_seekpoint;
717     if ( demux_Control( p_demux, DEMUX_GET_SEEKPOINT, &i_seekpoint ) == VLC_SUCCESS  )
718         return i_seekpoint;
719     return p_demux->info.i_seekpoint;
720 }
721
722 static demux_t *demux_FilterNew( demux_t *p_next, const char *p_name )
723 {
724     demux_priv_t *priv = vlc_custom_create(p_next, sizeof (*priv), "demux_filter");
725     if (unlikely(priv == NULL))
726         return NULL;
727
728     demux_t *p_demux = &priv->demux;
729
730     p_demux->p_next       = p_next;
731     p_demux->p_input      = NULL;
732     p_demux->p_sys        = NULL;
733     p_demux->psz_access   = NULL;
734     p_demux->psz_demux    = NULL;
735     p_demux->psz_location = NULL;
736     p_demux->psz_file     = NULL;
737     p_demux->out          = NULL;
738     priv->destroy         = demux_DestroyDemuxFilter;
739     p_demux->p_module =
740         module_need( p_demux, "demux_filter", p_name, p_name != NULL );
741
742     if( p_demux->p_module == NULL )
743         goto error;
744
745     return p_demux;
746 error:
747     vlc_object_release( p_demux );
748     return NULL;
749 }
750
751 demux_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_chain )
752 {
753     if( !psz_chain || !*psz_chain )
754         return NULL;
755
756     char *psz_parser = strdup(psz_chain);
757     if(!psz_parser)
758         return NULL;
759
760     vlc_array_t name;
761     vlc_array_init(&name);
762
763     /* parse chain */
764     while(psz_parser)
765     {
766         config_chain_t *p_cfg;
767         char *psz_name;
768         char *psz_rest_chain = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
769         free( psz_parser );
770         psz_parser = psz_rest_chain;
771
772         vlc_array_append(&name, psz_name);
773         config_ChainDestroy(p_cfg);
774     }
775
776     int i = vlc_array_count(&name);
777     vlc_array_t module;
778     vlc_array_init(&module);
779     while(i--)
780     {
781         const char *p_name = vlc_array_item_at_index(&name, i);
782         demux_t *p_next = demux_FilterNew( p_demux, p_name );
783         if(!p_next)
784             goto error;
785
786         vlc_array_append(&module, p_next);
787         p_demux = p_next;
788     }
789
790     vlc_array_clear(&name);
791     vlc_array_clear(&module);
792
793     return p_demux;
794  error:
795     i++;    /* last module couldn't be created */
796
797     /* destroy all modules created, starting with the last one */
798     int modules = vlc_array_count(&module);
799     while(modules--)
800         demux_Delete(vlc_array_item_at_index(&module, modules));
801     vlc_array_clear(&module);
802
803     while(i--)
804         free(vlc_array_item_at_index(&name, i));
805     vlc_array_clear(&name);
806
807     return NULL;
808 }