1 /*****************************************************************************
2  * demux.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VLC authors and VideoLAN
5  * $Id: 838ebe85911153ec4363d2466d84563b90bdf43c $
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 #include <limits.h>
30 
31 #include "demux.h"
32 #include <libvlc.h>
33 #include <vlc_codec.h>
34 #include <vlc_meta.h>
35 #include <vlc_url.h>
36 #include <vlc_modules.h>
37 #include <vlc_strings.h>
38 
39 typedef const struct
40 {
41     char const key[20];
42     char const name[8];
43 
44 } demux_mapping;
45 
demux_mapping_cmp(const void * k,const void * v)46 static int demux_mapping_cmp( const void *k, const void *v )
47 {
48     demux_mapping* entry = v;
49     return vlc_ascii_strcasecmp( k, entry->key );
50 }
51 
demux_lookup(char const * key,demux_mapping * data,size_t size)52 static demux_mapping* demux_lookup( char const* key,
53                                     demux_mapping* data, size_t size )
54 {
55     return bsearch( key, data, size, sizeof( *data ), demux_mapping_cmp );
56 }
57 
demux_NameFromMimeType(const char * mime)58 static const char *demux_NameFromMimeType(const char *mime)
59 {
60     static demux_mapping types[] =
61     {   /* Must be sorted in ascending ASCII order */
62         { "audio/aac",           "m4a"     },
63         { "audio/aacp",          "m4a"     },
64         { "audio/mpeg",          "mp3"     },
65         //{ "video/MP1S",          "es,mpgv" }, !b_force
66         { "video/dv",            "rawdv"   },
67         { "video/MP2P",          "ps"      },
68         { "video/MP2T",          "ts"      },
69         { "video/nsa",           "nsv"     },
70         { "video/nsv",           "nsv"     },
71     };
72     demux_mapping *type = demux_lookup( mime, types, ARRAY_SIZE( types ) );
73     return (type != NULL) ? type->name : "any";
74 }
75 
DemuxNameFromExtension(char const * ext,bool b_preparsing)76 static const char* DemuxNameFromExtension( char const* ext,
77                                            bool b_preparsing )
78 {
79     /* NOTE: Add only file without any problems here and with strong detection:
80      * - no .mp3, .a52, ...
81      *  - wav can't be added 'cause of a52 and dts in them as raw audio
82      */
83     static demux_mapping strong[] =
84     { /* NOTE: must be sorted in asc order */
85         { "aiff", "aiff" },
86         { "asf",  "asf" },
87         { "au",   "au" },
88         { "avi",  "avi" },
89         { "drc",  "dirac" },
90         { "dv",   "dv" },
91         { "flac", "flac" },
92         { "h264", "h264" },
93         { "kar", "smf" },
94         { "m3u",  "m3u" },
95         { "m4a",  "mp4" },
96         { "m4v",  "m4v" },
97         { "mid",  "smf" },
98         { "mka",  "mkv" },
99         { "mks",  "mkv" },
100         { "mkv",  "mkv" },
101         { "moov", "mp4" },
102         { "mov",  "mp4" },
103         { "mp4",  "mp4" },
104         { "nsv",  "nsv" },
105         { "oga",  "ogg" },
106         { "ogg",  "ogg" },
107         { "ogm",  "ogg" },
108         { "ogv",  "ogg" },
109         { "ogx",  "ogg" }, /*RFC5334*/
110         { "opus", "ogg" }, /*draft-terriberry-oggopus-01*/
111         { "pva",  "pva" },
112         { "rm",   "avformat" },
113         { "rmi",  "smf" },
114         { "spx",  "ogg" },
115         { "voc",  "voc" },
116         { "wma",  "asf" },
117         { "wmv",  "asf" },
118     };
119 
120     /* Here, we don't mind if it does not work, it must be quick */
121     static demux_mapping quick[] =
122     { /* NOTE: shall be sorted in asc order */
123         { "mp3", "mpga" },
124         { "ogg", "ogg" },
125         { "wma", "asf" },
126     };
127 
128     struct {
129         demux_mapping* data;
130         size_t size;
131 
132     } lookup = {
133         .data = b_preparsing ? quick : strong,
134         .size = b_preparsing ? ARRAY_SIZE( quick ) : ARRAY_SIZE( strong )
135     };
136 
137     demux_mapping* result = demux_lookup( ext, lookup.data, lookup.size );
138     return result ? result->name : NULL;
139 }
140 
141 /*****************************************************************************
142  * demux_New:
143  *  if s is NULL then load a access_demux
144  *****************************************************************************/
demux_New(vlc_object_t * p_obj,const char * psz_name,const char * psz_location,stream_t * s,es_out_t * out)145 demux_t *demux_New( vlc_object_t *p_obj, const char *psz_name,
146                     const char *psz_location, stream_t *s, es_out_t *out )
147 {
148     return demux_NewAdvanced( p_obj, NULL,
149                               (s == NULL) ? psz_name : "",
150                               (s != NULL) ? psz_name : "",
151                               psz_location, s, out, false );
152 }
153 
154 typedef struct demux_priv_t
155 {
156     demux_t demux;
157     void (*destroy)(demux_t *);
158 } demux_priv_t;
159 
demux_DestroyDemux(demux_t * demux)160 static void demux_DestroyDemux(demux_t *demux)
161 {
162     assert(demux->s != NULL);
163     vlc_stream_Delete(demux->s);
164 }
165 
demux_DestroyAccessDemux(demux_t * demux)166 static void demux_DestroyAccessDemux(demux_t *demux)
167 {
168     assert(demux->s == NULL);
169     (void) demux;
170 }
171 
demux_DestroyDemuxFilter(demux_t * demux)172 static void demux_DestroyDemuxFilter(demux_t *demux)
173 {
174     assert(demux->p_next != NULL);
175     demux_Delete(demux->p_next);
176 }
177 
demux_Probe(void * func,va_list ap)178 static int demux_Probe(void *func, va_list ap)
179 {
180     int (*probe)(vlc_object_t *) = func;
181     demux_t *demux = va_arg(ap, demux_t *);
182 
183     /* Restore input stream offset (in case previous probed demux failed to
184      * to do so). */
185     if (vlc_stream_Tell(demux->s) != 0 && vlc_stream_Seek(demux->s, 0))
186     {
187         msg_Err(demux, "seek failure before probing");
188         return VLC_EGENERIC;
189     }
190 
191     return probe(VLC_OBJECT(demux));
192 }
193 
194 /*****************************************************************************
195  * demux_NewAdvanced:
196  *  if s is NULL then load a access_demux
197  *****************************************************************************/
198 #undef demux_NewAdvanced
demux_NewAdvanced(vlc_object_t * p_obj,input_thread_t * p_parent_input,const char * psz_access,const char * psz_demux,const char * psz_location,stream_t * s,es_out_t * out,bool b_preparsing)199 demux_t *demux_NewAdvanced( vlc_object_t *p_obj, input_thread_t *p_parent_input,
200                             const char *psz_access, const char *psz_demux,
201                             const char *psz_location,
202                             stream_t *s, es_out_t *out, bool b_preparsing )
203 {
204     demux_priv_t *priv = vlc_custom_create(p_obj, sizeof (*priv), "demux");
205     if (unlikely(priv == NULL))
206         return NULL;
207 
208     demux_t *p_demux = &priv->demux;
209 
210     if( s != NULL && (!strcasecmp( psz_demux, "any" ) || !psz_demux[0]) )
211     {   /* Look up demux by mime-type for hard to detect formats */
212         char *type = stream_MimeType( s );
213         if( type != NULL )
214         {
215             psz_demux = demux_NameFromMimeType( type );
216             free( type );
217         }
218     }
219 
220     p_demux->p_input = p_parent_input;
221     p_demux->psz_access = strdup( psz_access );
222     p_demux->psz_demux = strdup( psz_demux );
223     p_demux->psz_location = strdup( psz_location );
224     p_demux->psz_file = get_path( psz_location ); /* parse URL */
225 
226     if( unlikely(p_demux->psz_access == NULL
227               || p_demux->psz_demux == NULL
228               || p_demux->psz_location == NULL) )
229         goto error;
230 
231     if( !b_preparsing )
232         msg_Dbg( p_obj, "creating demux: access='%s' demux='%s' "
233                  "location='%s' file='%s'",
234                  p_demux->psz_access, p_demux->psz_demux,
235                  p_demux->psz_location, p_demux->psz_file );
236 
237     p_demux->s              = s;
238     p_demux->out            = out;
239     p_demux->b_preparsing   = b_preparsing;
240 
241     p_demux->pf_demux   = NULL;
242     p_demux->pf_control = NULL;
243     p_demux->p_sys      = NULL;
244     p_demux->info.i_update = 0;
245     p_demux->info.i_title  = 0;
246     p_demux->info.i_seekpoint = 0;
247     priv->destroy = s ? demux_DestroyDemux : demux_DestroyAccessDemux;
248 
249     if( s != NULL )
250     {
251         const char *psz_module = NULL;
252 
253         if( !strcmp( p_demux->psz_demux, "any" ) && p_demux->psz_file )
254         {
255             char const* psz_ext = strrchr( p_demux->psz_file, '.' );
256 
257             if( psz_ext )
258                 psz_module = DemuxNameFromExtension( psz_ext + 1, b_preparsing );
259         }
260 
261         if( psz_module == NULL )
262             psz_module = p_demux->psz_demux;
263 
264         p_demux->p_module = vlc_module_load(p_demux, "demux", psz_module,
265              !strcmp(psz_module, p_demux->psz_demux), demux_Probe, p_demux);
266     }
267     else
268     {
269         p_demux->p_module =
270             module_need( p_demux, "access_demux", p_demux->psz_access, true );
271     }
272 
273     if( p_demux->p_module == NULL )
274         goto error;
275 
276     return p_demux;
277 error:
278     free( p_demux->psz_file );
279     free( p_demux->psz_location );
280     free( p_demux->psz_demux );
281     free( p_demux->psz_access );
282     vlc_object_release( p_demux );
283     return NULL;
284 }
285 
286 /*****************************************************************************
287  * demux_Delete:
288  *****************************************************************************/
demux_Delete(demux_t * p_demux)289 void demux_Delete( demux_t *p_demux )
290 {
291     demux_priv_t *priv = (demux_priv_t *)p_demux;
292 
293     module_unneed( p_demux, p_demux->p_module );
294 
295     priv->destroy(p_demux);
296     free( p_demux->psz_file );
297     free( p_demux->psz_location );
298     free( p_demux->psz_demux );
299     free( p_demux->psz_access );
300     vlc_object_release( p_demux );
301 }
302 
303 #define static_control_match(foo) \
304     static_assert((unsigned) DEMUX_##foo == STREAM_##foo, "Mismatch")
305 
demux_ControlInternal(demux_t * demux,int query,...)306 static int demux_ControlInternal( demux_t *demux, int query, ... )
307 {
308     int ret;
309     va_list ap;
310 
311     va_start( ap, query );
312     ret = demux->pf_control( demux, query, ap );
313     va_end( ap );
314     return ret;
315 }
316 
demux_vaControl(demux_t * demux,int query,va_list args)317 int demux_vaControl( demux_t *demux, int query, va_list args )
318 {
319     if( demux->s != NULL )
320         switch( query )
321         {
322             /* Legacy fallback for missing getters in synchronous demuxers */
323             case DEMUX_CAN_PAUSE:
324             case DEMUX_CAN_CONTROL_PACE:
325             case DEMUX_GET_PTS_DELAY:
326             {
327                 int ret;
328                 va_list ap;
329 
330                 va_copy( ap, args );
331                 ret = demux->pf_control( demux, query, args );
332                 if( ret != VLC_SUCCESS )
333                     ret = vlc_stream_vaControl( demux->s, query, ap );
334                 va_end( ap );
335                 return ret;
336             }
337 
338             /* Some demuxers need to control pause directly (e.g. adaptive),
339              * but many legacy demuxers do not understand pause at all.
340              * If DEMUX_CAN_PAUSE is not implemented, bypass the demuxer and
341              * byte stream. If DEMUX_CAN_PAUSE is implemented and pause is
342              * supported, pause the demuxer normally. Else, something went very
343              * wrong.
344              *
345              * Note that this requires asynchronous/threaded demuxers to
346              * always return VLC_SUCCESS for DEMUX_CAN_PAUSE, so that they are
347              * never bypassed. Otherwise, we would reenter demux->s callbacks
348              * and break thread safety. At the time of writing, asynchronous or
349              * threaded *non-access* demuxers do not exist and are not fully
350              * supported by the input thread, so this is theoretical. */
351             case DEMUX_SET_PAUSE_STATE:
352             {
353                 bool can_pause;
354 
355                 if( demux_ControlInternal( demux, DEMUX_CAN_PAUSE,
356                                            &can_pause ) )
357                     return vlc_stream_vaControl( demux->s, query, args );
358 
359                 /* The caller shall not pause if pause is unsupported. */
360                 assert( can_pause );
361                 break;
362             }
363         }
364 
365     return demux->pf_control( demux, query, args );
366 }
367 
368 /*****************************************************************************
369  * demux_vaControlHelper:
370  *****************************************************************************/
demux_vaControlHelper(stream_t * s,int64_t i_start,int64_t i_end,int64_t i_bitrate,int i_align,int i_query,va_list args)371 int demux_vaControlHelper( stream_t *s,
372                             int64_t i_start, int64_t i_end,
373                             int64_t i_bitrate, int i_align,
374                             int i_query, va_list args )
375 {
376     int64_t i_tell;
377     double  f, *pf;
378     int64_t i64, *pi64;
379 
380     if( i_end < 0 )    i_end   = stream_Size( s );
381     if( i_start < 0 )  i_start = 0;
382     if( i_align <= 0 ) i_align = 1;
383     i_tell = vlc_stream_Tell( s );
384 
385     static_control_match(CAN_PAUSE);
386     static_control_match(CAN_CONTROL_PACE);
387     static_control_match(GET_PTS_DELAY);
388     static_control_match(GET_META);
389     static_control_match(GET_SIGNAL);
390     static_control_match(SET_PAUSE_STATE);
391 
392     switch( i_query )
393     {
394         case DEMUX_CAN_SEEK:
395         {
396             bool *b = va_arg( args, bool * );
397 
398             if( (i_bitrate <= 0 && i_start >= i_end)
399              || vlc_stream_Control( s, STREAM_CAN_SEEK, b ) )
400                 *b = false;
401             break;
402         }
403 
404         case DEMUX_CAN_PAUSE:
405         case DEMUX_CAN_CONTROL_PACE:
406         case DEMUX_GET_PTS_DELAY:
407         case DEMUX_GET_META:
408         case DEMUX_GET_SIGNAL:
409         case DEMUX_SET_PAUSE_STATE:
410             return vlc_stream_vaControl( s, i_query, args );
411 
412         case DEMUX_GET_LENGTH:
413             pi64 = (int64_t*)va_arg( args, int64_t * );
414             if( i_bitrate > 0 && i_end > i_start )
415             {
416                 *pi64 = INT64_C(8000000) * (i_end - i_start) / i_bitrate;
417                 return VLC_SUCCESS;
418             }
419             return VLC_EGENERIC;
420 
421         case DEMUX_GET_TIME:
422             pi64 = (int64_t*)va_arg( args, int64_t * );
423             if( i_bitrate > 0 && i_tell >= i_start )
424             {
425                 *pi64 = INT64_C(8000000) * (i_tell - i_start) / i_bitrate;
426                 return VLC_SUCCESS;
427             }
428             return VLC_EGENERIC;
429 
430         case DEMUX_GET_POSITION:
431             pf = (double*)va_arg( args, double * );
432             if( i_start < i_end )
433             {
434                 *pf = (double)( i_tell - i_start ) /
435                       (double)( i_end  - i_start );
436                 return VLC_SUCCESS;
437             }
438             return VLC_EGENERIC;
439 
440 
441         case DEMUX_SET_POSITION:
442             f = (double)va_arg( args, double );
443             if( i_start < i_end && f >= 0.0 && f <= 1.0 )
444             {
445                 int64_t i_block = (f * ( i_end - i_start )) / i_align;
446 
447                 if( vlc_stream_Seek( s, i_start + i_block * i_align ) )
448                 {
449                     return VLC_EGENERIC;
450                 }
451                 return VLC_SUCCESS;
452             }
453             return VLC_EGENERIC;
454 
455         case DEMUX_SET_TIME:
456             i64 = (int64_t)va_arg( args, int64_t );
457             if( i_bitrate > 0 && i64 >= 0 )
458             {
459                 int64_t i_block = i64 * i_bitrate / INT64_C(8000000) / i_align;
460                 if( vlc_stream_Seek( s, i_start + i_block * i_align ) )
461                 {
462                     return VLC_EGENERIC;
463                 }
464                 return VLC_SUCCESS;
465             }
466             return VLC_EGENERIC;
467 
468         case DEMUX_IS_PLAYLIST:
469             *va_arg( args, bool * ) = false;
470             return VLC_SUCCESS;
471 
472         case DEMUX_GET_FPS:
473         case DEMUX_HAS_UNSUPPORTED_META:
474         case DEMUX_SET_NEXT_DEMUX_TIME:
475         case DEMUX_GET_TITLE_INFO:
476         case DEMUX_SET_GROUP:
477         case DEMUX_SET_ES:
478         case DEMUX_GET_ATTACHMENTS:
479         case DEMUX_CAN_RECORD:
480         case DEMUX_TEST_AND_CLEAR_FLAGS:
481         case DEMUX_GET_TITLE:
482         case DEMUX_GET_SEEKPOINT:
483         case DEMUX_NAV_ACTIVATE:
484         case DEMUX_NAV_UP:
485         case DEMUX_NAV_DOWN:
486         case DEMUX_NAV_LEFT:
487         case DEMUX_NAV_RIGHT:
488         case DEMUX_NAV_POPUP:
489         case DEMUX_NAV_MENU:
490         case DEMUX_FILTER_ENABLE:
491         case DEMUX_FILTER_DISABLE:
492             return VLC_EGENERIC;
493 
494         case DEMUX_SET_TITLE:
495         case DEMUX_SET_SEEKPOINT:
496         case DEMUX_SET_RECORD_STATE:
497             assert(0);
498         default:
499             msg_Err( s, "unknown query 0x%x in %s", i_query, __func__ );
500             return VLC_EGENERIC;
501     }
502     return VLC_SUCCESS;
503 }
504 
505 /****************************************************************************
506  * Utility functions
507  ****************************************************************************/
demux_PacketizerNew(demux_t * p_demux,es_format_t * p_fmt,const char * psz_msg)508 decoder_t *demux_PacketizerNew( demux_t *p_demux, es_format_t *p_fmt, const char *psz_msg )
509 {
510     decoder_t *p_packetizer;
511     p_packetizer = vlc_custom_create( p_demux, sizeof( *p_packetizer ),
512                                       "demux packetizer" );
513     if( !p_packetizer )
514     {
515         es_format_Clean( p_fmt );
516         return NULL;
517     }
518     p_fmt->b_packetized = false;
519 
520     p_packetizer->pf_decode = NULL;
521     p_packetizer->pf_packetize = NULL;
522 
523     p_packetizer->fmt_in = *p_fmt;
524     es_format_Init( &p_packetizer->fmt_out, p_fmt->i_cat, 0 );
525 
526     p_packetizer->p_module = module_need( p_packetizer, "packetizer", NULL, false );
527     if( !p_packetizer->p_module )
528     {
529         es_format_Clean( p_fmt );
530         vlc_object_release( p_packetizer );
531         msg_Err( p_demux, "cannot find packetizer for %s", psz_msg );
532         return NULL;
533     }
534 
535     return p_packetizer;
536 }
537 
demux_PacketizerDestroy(decoder_t * p_packetizer)538 void demux_PacketizerDestroy( decoder_t *p_packetizer )
539 {
540     if( p_packetizer->p_module )
541         module_unneed( p_packetizer, p_packetizer->p_module );
542     es_format_Clean( &p_packetizer->fmt_in );
543     es_format_Clean( &p_packetizer->fmt_out );
544     if( p_packetizer->p_description )
545         vlc_meta_Delete( p_packetizer->p_description );
546     vlc_object_release( p_packetizer );
547 }
548 
demux_TestAndClearFlags(demux_t * p_demux,unsigned flags)549 unsigned demux_TestAndClearFlags( demux_t *p_demux, unsigned flags )
550 {
551     unsigned update = flags;
552 
553     if ( demux_Control( p_demux, DEMUX_TEST_AND_CLEAR_FLAGS, &update ) == VLC_SUCCESS )
554         return update;
555 
556     update = p_demux->info.i_update & flags;
557     p_demux->info.i_update &= ~flags;
558     return update;
559 }
560 
demux_GetTitle(demux_t * p_demux)561 int demux_GetTitle( demux_t *p_demux )
562 {
563     int i_title;
564     if ( demux_Control( p_demux, DEMUX_GET_TITLE, &i_title ) == VLC_SUCCESS )
565         return i_title;
566     return p_demux->info.i_title;
567 }
568 
demux_GetSeekpoint(demux_t * p_demux)569 int demux_GetSeekpoint( demux_t *p_demux )
570 {
571     int i_seekpoint;
572     if ( demux_Control( p_demux, DEMUX_GET_SEEKPOINT, &i_seekpoint ) == VLC_SUCCESS  )
573         return i_seekpoint;
574     return p_demux->info.i_seekpoint;
575 }
576 
demux_FilterNew(demux_t * p_next,const char * p_name)577 static demux_t *demux_FilterNew( demux_t *p_next, const char *p_name )
578 {
579     demux_priv_t *priv = vlc_custom_create(p_next, sizeof (*priv), "demux_filter");
580     if (unlikely(priv == NULL))
581         return NULL;
582 
583     demux_t *p_demux = &priv->demux;
584 
585     p_demux->p_next       = p_next;
586     p_demux->p_input      = NULL;
587     p_demux->p_sys        = NULL;
588     p_demux->psz_access   = NULL;
589     p_demux->psz_demux    = NULL;
590     p_demux->psz_location = NULL;
591     p_demux->psz_file     = NULL;
592     p_demux->out          = NULL;
593     priv->destroy         = demux_DestroyDemuxFilter;
594     p_demux->p_module =
595         module_need( p_demux, "demux_filter", p_name, p_name != NULL );
596 
597     if( p_demux->p_module == NULL )
598         goto error;
599 
600     return p_demux;
601 error:
602     vlc_object_release( p_demux );
603     return NULL;
604 }
605 
demux_FilterChainNew(demux_t * p_demux,const char * psz_chain)606 demux_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_chain )
607 {
608     if( !psz_chain || !*psz_chain )
609         return NULL;
610 
611     char *psz_parser = strdup(psz_chain);
612     if(!psz_parser)
613         return NULL;
614 
615     /* parse chain */
616     while(psz_parser)
617     {
618         config_chain_t *p_cfg;
619         char *psz_name;
620         char *psz_rest_chain = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
621         free( psz_parser );
622         psz_parser = psz_rest_chain;
623 
624         demux_t *filter = demux_FilterNew(p_demux, psz_name);
625         if (filter != NULL)
626             p_demux = filter;
627 
628         free(psz_name);
629         config_ChainDestroy(p_cfg);
630     }
631 
632     return p_demux;
633 }
634 
demux_filter_enable_disable(demux_t * p_demux_chain,const char * psz_demux,bool b_enable)635 static bool demux_filter_enable_disable( demux_t *p_demux_chain,
636                                           const char* psz_demux, bool b_enable )
637 {
638     demux_t *p_demux = p_demux_chain;
639 
640      if( strcmp( module_get_name( p_demux->p_module, false ), psz_demux) == 0 ||
641          strcmp( module_get_name( p_demux->p_module, true ), psz_demux ) == 0 )
642      {
643         demux_Control( p_demux,
644                        b_enable ? DEMUX_FILTER_ENABLE : DEMUX_FILTER_DISABLE );
645         return true;
646     }
647     return false;
648 }
649 
demux_FilterEnable(demux_t * p_demux_chain,const char * psz_demux)650 bool demux_FilterEnable( demux_t *p_demux_chain, const char* psz_demux )
651 {
652     return demux_filter_enable_disable( p_demux_chain, psz_demux, true );
653 }
654 
demux_FilterDisable(demux_t * p_demux_chain,const char * psz_demux)655 bool demux_FilterDisable( demux_t *p_demux_chain, const char* psz_demux )
656 {
657     return demux_filter_enable_disable( p_demux_chain, psz_demux, false );
658 }
659