]> git.sesse.net Git - vlc/blobdiff - modules/demux/ts.c
demux: ts: rewrite/split IOD parsing
[vlc] / modules / demux / ts.c
index 35e0626900547cdc9b44f5f26c4adabed3e76a0e..2e36f05ba63187b56a3e817602684341b486d7b1 100644 (file)
 
 #include "opus.h"
 
-#undef TS_DEBUG
-VLC_FORMAT(1, 2) static void ts_debug(const char *format, ...)
-{
-#ifdef TS_DEBUG
-    va_list ap;
-    va_start(ap, format);
-    vfprintf(stderr, format, ap);
-    va_end(ap);
-#else
-    (void)format;
-#endif
-}
+#include "mpeg4_iod.h"
 
 #ifdef HAVE_ARIBB24
  #include <aribb24/aribb24.h>
@@ -204,37 +193,6 @@ static const char *const ppsz_teletext_type[] = {
 
 typedef struct ts_pid_t ts_pid_t;
 
-typedef struct
-{
-    uint8_t                 i_objectTypeIndication;
-    uint8_t                 i_streamType;
-
-    int                     i_extra;
-    uint8_t                 *p_extra;
-
-} decoder_config_descriptor_t;
-
-typedef struct
-{
-    bool                    b_ok;
-    uint16_t                i_es_id;
-
-    char                    *psz_url;
-
-    decoder_config_descriptor_t    dec_descr;
-
-} es_mpeg4_descriptor_t;
-
-#define ES_DESCRIPTOR_COUNT 255
-typedef struct
-{
-    /* IOD */
-    char                    *psz_url;
-
-    es_mpeg4_descriptor_t   es_descr[ES_DESCRIPTOR_COUNT];
-
-} iod_descriptor_t;
-
 typedef struct
 {
     int             i_version;
@@ -263,6 +221,7 @@ typedef struct
         mtime_t i_first_dts;
         mtime_t i_pcroffset;
         bool    b_disable; /* ignore PCR field, use dts */
+        bool    b_fix_done;
     } pcr;
 
     mtime_t i_last_dts;
@@ -273,7 +232,7 @@ typedef struct
 {
     es_format_t  fmt;
     es_out_id_t *id;
-    es_mpeg4_descriptor_t *p_mpeg4desc;
+    const es_mpeg4_descriptor_t *p_mpeg4desc;
 } ts_pes_es_t;
 
 typedef enum
@@ -313,21 +272,6 @@ typedef enum
     TS_PMT_REGISTRATION_HDMV
 } ts_pmt_registration_type_t;
 
-typedef struct
-{
-    es_format_t  fmt;
-    es_out_id_t *id;
-    ts_es_data_type_t data_type;
-    int         i_data_size;
-    int         i_data_gathered;
-    block_t     *p_data;
-    block_t    **pp_last;
-
-    es_mpeg4_descriptor_t *p_mpeg4desc;
-
-    block_t *   p_prepcr_outqueue;
-} ts_es_t;
-
 typedef enum
 {
     TYPE_FREE = 0,
@@ -347,7 +291,7 @@ enum
     FLAG_FILTERED = 4
 };
 
-#define SEEN(x) ((x).i_flags & FLAG_SEEN)
+#define SEEN(x) ((x)->i_flags & FLAG_SEEN)
 #define SCRAMBLED(x) ((x).i_flags & FLAG_SCRAMBLED)
 
 struct ts_pid_t
@@ -392,6 +336,8 @@ typedef struct
 #define FROM_SCALE(x) (VLC_TS_0 + ((x) * 100 / 9))
 #define TO_SCALE(x)   (((x) - VLC_TS_0) * 9 / 100)
 
+#define PID_ALLOC_CHUNK 16
+
 struct demux_sys_t
 {
     stream_t   *stream;
@@ -400,13 +346,13 @@ struct demux_sys_t
     vlc_mutex_t     csa_lock;
 
     /* TS packet size (188, 192, 204) */
-    int         i_packet_size;
+    unsigned    i_packet_size;
 
     /* Additional TS packet header size (BluRay TS packets have 4-byte header before sync byte) */
-    int         i_packet_header_size;
+    unsigned    i_packet_header_size;
 
     /* how many TS packet we read at once */
-    int         i_ts_read;
+    unsigned    i_ts_read;
 
     bool        b_force_seek_per_percent;
 
@@ -420,7 +366,18 @@ struct demux_sys_t
     } arib;
 
     /* All pid */
-    ts_pid_t    pid[8192];
+    struct
+    {
+        ts_pid_t pat;
+        ts_pid_t dummy;
+        /* all non commons ones, dynamically allocated */
+        ts_pid_t **pp_all;
+        int        i_all;
+        int        i_all_alloc;
+        /* last recently used */
+        uint16_t   i_last_pid;
+        ts_pid_t  *p_last;
+    } pids;
 
     bool        b_user_pmt;
     int         i_pmt_es;
@@ -436,6 +393,8 @@ struct demux_sys_t
 
     /* */
     bool        b_es_id_pid;
+    uint16_t    i_next_extraid;
+
     csa_t       *csa;
     int         i_csa_pkt_size;
     bool        b_split_es;
@@ -496,6 +455,7 @@ static ts_psi_t *ts_psi_New( demux_t * );
 static void ts_psi_Del( demux_t *, ts_psi_t * );
 
 /* Helpers */
+static ts_pid_t *PID( demux_sys_t *, uint16_t i_pid );
 static ts_pmt_t * GetProgramByID( demux_sys_t *, int i_program );
 static bool ProgramIsSelected( demux_sys_t *, uint16_t i_pgrm );
 static void UpdatePESFilters( demux_t *p_demux, bool b_all );
@@ -519,8 +479,6 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
 static void PCRFixHandle( demux_t *, ts_pmt_t *, block_t * );
 static int64_t TimeStampWrapAround( ts_pmt_t *, int64_t );
 
-static void              IODFree( iod_descriptor_t * );
-
 #define TS_USER_PMT_NUMBER (0)
 static int UserPmt( demux_t *p_demux, const char * );
 
@@ -532,7 +490,7 @@ static int  SetPIDFilter( demux_sys_t *, ts_pid_t *, bool b_selected );
 #define TS_PACKET_SIZE_MAX 204
 #define TS_HEADER_SIZE 4
 
-static int DetectPacketSize( demux_t *p_demux, int *pi_header_size, int i_offset )
+static int DetectPacketSize( demux_t *p_demux, unsigned *pi_header_size, int i_offset )
 {
     const uint8_t *p_peek;
 
@@ -587,7 +545,7 @@ static int DetectPacketSize( demux_t *p_demux, int *pi_header_size, int i_offset
 
 #define TOPFIELD_HEADER_SIZE 3712
 
-static int DetectPVRHeadersAndHeaderSize( demux_t *p_demux, int *pi_header_size, vdr_info_t *p_vdr )
+static int DetectPVRHeadersAndHeaderSize( demux_t *p_demux, unsigned *pi_header_size, vdr_info_t *p_vdr )
 {
     const uint8_t *p_peek;
     *pi_header_size = 0;
@@ -894,23 +852,28 @@ static void MissingPATPMTFixup( demux_t *p_demux )
     int i_pcr_pid = 0x1FFF;
     int i_num_pes = 0;
 
-    if( SEEN(p_sys->pid[i_program_pid]) )
+    ts_pid_t *p_program_pid = PID( p_sys, i_program_pid );
+    if( SEEN(p_program_pid) )
     {
         /* Find a free one */
         for( i_program_pid = MIN_ES_PID;
-             i_program_pid <= MAX_ES_PID && SEEN(p_sys->pid[i_program_pid]);
-             i_program_pid++ );
+             i_program_pid <= MAX_ES_PID && SEEN(p_program_pid);
+             i_program_pid++ )
+        {
+            p_program_pid = PID( p_sys, i_program_pid );
+        }
     }
 
-    for( int i = MIN_ES_PID; i <= MAX_ES_PID; i++ )
+    for( int i=0; i<p_sys->pids.i_all; i++ )
     {
-        if( !SEEN(p_sys->pid[i]) ||
-            p_sys->pid[i].probed.i_type == -1 )
+        const ts_pid_t *p_pid = p_sys->pids.pp_all[i];
+        if( !SEEN(p_pid) ||
+            p_pid->probed.i_type == -1 )
             continue;
 
-        if( i_pcr_pid == 0x1FFF && ( p_sys->pid[i].probed.i_type == 0x03 ||
-                                     p_sys->pid[i].probed.i_pcr_count ) )
-            i_pcr_pid = p_sys->pid[i].i_pid;
+        if( i_pcr_pid == 0x1FFF && ( p_pid->probed.i_type == 0x03 ||
+                                     p_pid->probed.i_pcr_count ) )
+            i_pcr_pid = p_pid->i_pid;
 
         i_num_pes++;
     }
@@ -932,13 +895,14 @@ static void MissingPATPMTFixup( demux_t *p_demux )
         .b_discontinuity = false
     };
 
-    BuildPAT( p_sys->pid[0].u.p_pat->handle,
-            &p_sys->pid[0], BuildPATCallback,
+    BuildPAT( PID(p_sys, 0)->u.p_pat->handle,
+            &p_sys->pids.pat, BuildPATCallback,
             0, 1,
             &patstream,
             1, &pmtprogramstream, &i_program_number );
 
-    if( p_sys->pid[i_program_pid].type != TYPE_PMT )
+    /* PAT callback should have been triggered */
+    if( p_program_pid->type != TYPE_PMT )
     {
         msg_Err( p_demux, "PAT creation failed" );
         return;
@@ -955,23 +919,25 @@ static void MissingPATPMTFixup( demux_t *p_demux )
     if( esstreams && mapped )
     {
         int j=0;
-        for( int i = MIN_ES_PID; i <= MAX_ES_PID; i++ )
+        for( int i=0; i<p_sys->pids.i_all; i++ )
         {
-            if( !SEEN(p_sys->pid[i]) ||
-                p_sys->pid[i].probed.i_type == -1 )
+            const ts_pid_t *p_pid = p_sys->pids.pp_all[i];
+
+            if( !SEEN(p_pid) ||
+                p_pid->probed.i_type == -1 )
                 continue;
 
-            esstreams[j].pes.i_stream_type = p_sys->pid[i].probed.i_type;
-            esstreams[j].pes.i_stream_type = p_sys->pid[i].probed.i_type;
-            esstreams[j].ts.i_pid = p_sys->pid[i].i_pid;
+            esstreams[j].pes.i_stream_type = p_pid->probed.i_type;
+            esstreams[j].pes.i_stream_type = p_pid->probed.i_type;
+            esstreams[j].ts.i_pid = p_pid->i_pid;
             mapped[j].pes = &esstreams[j].pes;
             mapped[j].ts = &esstreams[j].ts;
             mapped[j].fmt = &esfmt;
             j++;
         }
 
-        BuildPMT( p_sys->pid[0].u.p_pat->handle, VLC_OBJECT(p_demux),
-                &p_sys->pid[i_program_pid], BuildPMTCallback,
+        BuildPMT( PID(p_sys, 0)->u.p_pat->handle, VLC_OBJECT(p_demux),
+                p_program_pid, BuildPMTCallback,
                 0, 1,
                 i_pcr_pid,
                 NULL,
@@ -990,7 +956,8 @@ static int Open( vlc_object_t *p_this )
     demux_t     *p_demux = (demux_t*)p_this;
     demux_sys_t *p_sys;
 
-    int          i_packet_size, i_packet_header_size = 0;
+    int          i_packet_size;
+    unsigned     i_packet_header_size = 0;
 
     ts_pid_t    *patpid;
     vdr_info_t   vdr = {0};
@@ -1026,16 +993,9 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->b_broken_charset = false;
 
-    for( int i = 0; i < 8192; i++ )
-    {
-        ts_pid_t *pid = &p_sys->pid[i];
-        pid->i_pid      = i;
-        pid->i_flags    = FLAGS_NONE;
-        pid->probed.i_fourcc = 0;
-        pid->probed.i_type = 0;
-    }
-    /* PID 8191 is padding */
-    p_sys->pid[8191].i_flags = FLAG_SEEN;
+    p_sys->pids.dummy.i_pid = 8191;
+    p_sys->pids.dummy.i_flags = FLAG_SEEN;
+
     p_sys->i_packet_size = i_packet_size;
     p_sys->i_packet_header_size = i_packet_header_size;
     p_sys->i_ts_read = 50;
@@ -1051,7 +1011,7 @@ static int Open( vlc_object_t *p_this )
     } while (0)
 
     /* Init PAT handler */
-    patpid = &p_sys->pid[0];
+    patpid = PID(p_sys, 0);
     if ( !PIDSetup( p_demux, TYPE_PAT, patpid, NULL ) )
     {
         vlc_mutex_destroy( &p_sys->csa_lock );
@@ -1068,24 +1028,24 @@ static int Open( vlc_object_t *p_this )
 
     if( p_sys->b_dvb_meta )
     {
-          if( !PIDSetup( p_demux, TYPE_SDT, &p_sys->pid[0x11], NULL ) ||
-              !PIDSetup( p_demux, TYPE_EIT, &p_sys->pid[0x12], NULL ) ||
-              !PIDSetup( p_demux, TYPE_TDT, &p_sys->pid[0x14], NULL ) )
+          if( !PIDSetup( p_demux, TYPE_SDT, PID(p_sys, 0x11), NULL ) ||
+              !PIDSetup( p_demux, TYPE_EIT, PID(p_sys, 0x12), NULL ) ||
+              !PIDSetup( p_demux, TYPE_TDT, PID(p_sys, 0x14), NULL ) )
           {
-              PIDRelease( p_demux, &p_sys->pid[0x11] );
-              PIDRelease( p_demux, &p_sys->pid[0x12] );
-              PIDRelease( p_demux, &p_sys->pid[0x14] );
+              PIDRelease( p_demux, PID(p_sys, 0x11) );
+              PIDRelease( p_demux, PID(p_sys, 0x12) );
+              PIDRelease( p_demux, PID(p_sys, 0x14) );
               p_sys->b_dvb_meta = false;
           }
           else
           {
-              VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x11], p_demux);
-              VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x12], p_demux);
-              VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x14], p_demux);
+              VLC_DVBPSI_DEMUX_TABLE_INIT(PID(p_sys, 0x11), p_demux);
+              VLC_DVBPSI_DEMUX_TABLE_INIT(PID(p_sys, 0x12), p_demux);
+              VLC_DVBPSI_DEMUX_TABLE_INIT(PID(p_sys, 0x14), p_demux);
               if( p_sys->b_access_control &&
-                  ( SetPIDFilter( p_sys, &p_sys->pid[0x11], true ) ||
-                    SetPIDFilter( p_sys, &p_sys->pid[0x14], true ) ||
-                    SetPIDFilter( p_sys, &p_sys->pid[0x12], true ) )
+                  ( SetPIDFilter( p_sys, PID(p_sys, 0x11), true ) ||
+                    SetPIDFilter( p_sys, PID(p_sys, 0x14), true ) ||
+                    SetPIDFilter( p_sys, PID(p_sys, 0x12), true ) )
                  )
                      p_sys->b_access_control = false;
           }
@@ -1098,6 +1058,7 @@ static int Open( vlc_object_t *p_this )
 
     /* Read config */
     p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" );
+    p_sys->i_next_extraid = 1;
 
     p_sys->b_trust_pcr = var_CreateGetBool( p_demux, "ts-trust-pcr" );
 
@@ -1189,24 +1150,15 @@ static void Close( vlc_object_t *p_this )
     demux_t     *p_demux = (demux_t*)p_this;
     demux_sys_t *p_sys = p_demux->p_sys;
 
-    PIDRelease( p_demux, &p_sys->pid[0] );
+    PIDRelease( p_demux, PID(p_sys, 0) );
 
     if( p_sys->b_dvb_meta )
     {
-        PIDRelease( p_demux, &p_sys->pid[0x11] );
-        PIDRelease( p_demux, &p_sys->pid[0x12] );
-        PIDRelease( p_demux, &p_sys->pid[0x14] );
+        PIDRelease( p_demux, PID(p_sys, 0x11) );
+        PIDRelease( p_demux, PID(p_sys, 0x12) );
+        PIDRelease( p_demux, PID(p_sys, 0x14) );
     }
 
-#ifndef NDEBUG
-    for( int i = 0; i < 8192; i++ )
-    {
-        ts_pid_t *pid = &p_sys->pid[i];
-        if( pid->type != TYPE_FREE )
-            msg_Err( p_demux, "PID %d type %d not freed", pid->i_pid, pid->type );
-    }
-#endif
-
     vlc_mutex_lock( &p_sys->csa_lock );
     if( p_sys->csa )
     {
@@ -1230,6 +1182,19 @@ static void Close( vlc_object_t *p_this )
     }
 
     vlc_mutex_destroy( &p_sys->csa_lock );
+
+    /* Release all non default pids */
+    for( int i = 0; i < p_sys->pids.i_all; i++ )
+    {
+        ts_pid_t *pid = p_sys->pids.pp_all[i];
+#ifndef NDEBUG
+        if( pid->type != TYPE_FREE )
+            msg_Err( p_demux, "PID %d type %d not freed", pid->i_pid, pid->type );
+#endif
+        free( pid );
+    }
+    free( p_sys->pids.pp_all );
+
     free( p_sys );
 }
 
@@ -1264,11 +1229,11 @@ static int Demux( demux_t *p_demux )
     bool b_wait_es = p_sys->i_pmt_es <= 0;
 
     /* If we had no PAT within MIN_PAT_INTERVAL, create PAT/PMT from probed streams */
-    if( p_sys->i_pmt_es == 0 && !SEEN(p_sys->pid[0]) && p_sys->patfix.b_pat_deadline )
+    if( p_sys->i_pmt_es == 0 && !SEEN(PID(p_sys, 0)) && p_sys->patfix.b_pat_deadline )
         MissingPATPMTFixup( p_demux );
 
     /* We read at most 100 TS packet or until a frame is completed */
-    for( int i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
+    for( unsigned i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
     {
         bool         b_frame = false;
         block_t     *p_pkt;
@@ -1285,12 +1250,12 @@ static int Demux( demux_t *p_demux )
         }
 
         /* Parse the TS packet */
-        ts_pid_t *p_pid = &p_sys->pid[PIDGet( p_pkt )];
+        ts_pid_t *p_pid = PID( p_sys, PIDGet( p_pkt ) );
 
         if( SCRAMBLED(*p_pid) != !!(p_pkt->p_buffer[3] & 0x80) )
             UpdateScrambledState( p_demux, p_pid, p_pkt->p_buffer[3] & 0x80 );
 
-        if( !SEEN(*p_pid) )
+        if( !SEEN(p_pid) )
         {
             if( p_pid->type == TYPE_FREE )
                 msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid );
@@ -1304,7 +1269,7 @@ static int Demux( demux_t *p_demux )
         }
 
         /* Probe streams to build PAT/PMT after MIN_PAT_INTERVAL in case we don't see any PAT */
-        if( !SEEN(p_sys->pid[0]) &&
+        if( !SEEN( PID( p_sys, 0 ) ) &&
             (p_pid->probed.i_type == 0 || p_pid->i_pid == p_sys->patfix.i_timesourcepid) &&
             (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */
             (p_pkt->p_buffer[3] & 0xD0) == 0x10 )  /* Has payload but is not encrypted */
@@ -1397,7 +1362,7 @@ static int DVBEventInformation( demux_t *p_demux, int64_t *pi_time, int64_t *pi_
 static void UpdatePESFilters( demux_t *p_demux, bool b_all )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
-    ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+    ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
     for( int i=0; i< p_pat->programs.i_size; i++ )
     {
         ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
@@ -1408,12 +1373,6 @@ static void UpdatePESFilters( demux_t *p_demux, bool b_all )
              b_program_selected = ProgramIsSelected( p_sys, p_pmt->i_number );
 
         SetPIDFilter( p_sys, p_pat->programs.p_elems[i], b_program_selected );
-        if( p_pmt->i_pid_pcr > 0 )
-        {
-            SetPIDFilter( p_sys, &p_sys->pid[p_pmt->i_pid_pcr], b_program_selected );
-            if( b_program_selected )
-                msg_Dbg( p_demux, "enabling pcr pid %d from program %d", p_pmt->i_pid_pcr, p_pmt->i_number );
-        }
 
         for( int j=0; j<p_pmt->e_streams.i_size; j++ )
         {
@@ -1434,6 +1393,13 @@ static void UpdatePESFilters( demux_t *p_demux, bool b_all )
                 FlushESBuffer( espid->u.p_pes );
         }
 
+        /* Select pcr last in case it is handled by unselected ES */
+        if( p_pmt->i_pid_pcr > 0 )
+        {
+            SetPIDFilter( p_sys, PID(p_sys, p_pmt->i_pid_pcr), b_program_selected );
+            if( b_program_selected )
+                msg_Dbg( p_demux, "enabling pcr pid %d from program %d", p_pmt->i_pid_pcr, p_pmt->i_number );
+        }
     }
 }
 
@@ -1450,9 +1416,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
 
     if( PREPARSING || !i_first_program || p_sys->b_default_selection )
     {
-        if( likely(p_sys->pid[0].type == TYPE_PAT) )
+        if( likely(PID(p_sys, 0)->type == TYPE_PAT) )
         {
-            ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+            ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
             /* Set default program for preparse time (no program has been selected) */
             for( int i = 0; i < p_pat->programs.i_size; i++ )
             {
@@ -1633,7 +1599,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             else // All ES Mode
             {
                 p_sys->b_es_all = true;
-                ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+                ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
                 for( int i = 0; i < p_pat->programs.i_size; i++ )
                    ARRAY_APPEND( p_sys->programs, p_pat->programs.p_elems[i]->i_pid );
                 UpdatePESFilters( p_demux, true );
@@ -1723,10 +1689,10 @@ static int UserPmt( demux_t *p_demux, const char *psz_fmt )
         i_number = strtol( &psz[1], &psz, 0 );
 
     /* */
-    ts_pid_t *pmtpid = &p_sys->pid[i_pid];
+    ts_pid_t *pmtpid = PID(p_sys, i_pid);
 
     msg_Dbg( p_demux, "user pmt specified (pid=%d,number=%d)", i_pid, i_number );
-    if ( !PIDSetup( p_demux, TYPE_PMT, pmtpid, &p_sys->pid[0] ) )
+    if ( !PIDSetup( p_demux, TYPE_PMT, pmtpid, PID(p_sys, 0) ) )
         goto error;
 
     /* Dummy PMT */
@@ -1740,7 +1706,7 @@ static int UserPmt( demux_t *p_demux, const char *psz_fmt )
         goto error;
     }
 
-    ARRAY_APPEND( p_sys->pid[0].u.p_pat->programs, pmtpid );
+    ARRAY_APPEND( PID(p_sys, 0)->u.p_pat->programs, pmtpid );
 
     psz = strchr( psz, '=' );
     if( psz )
@@ -1762,9 +1728,9 @@ static int UserPmt( demux_t *p_demux, const char *psz_fmt )
         {
             p_pmt->i_pid_pcr = i_pid;
         }
-        else if( p_sys->pid[i_pid].type == TYPE_FREE )
+        else if( PID(p_sys, i_pid)->type == TYPE_FREE )
         {
-            ts_pid_t *pid = &p_sys->pid[i_pid];
+            ts_pid_t *pid = PID(p_sys, i_pid);
 
             char *psz_arg = strchr( psz_opt, '=' );
             if( psz_arg )
@@ -2055,7 +2021,7 @@ static block_t *Opus_Parse(demux_t *demux, block_t *block)
         last = &au->p_next;
 
         au->i_nb_samples = opus_frame_duration(buf, au_size);
-        if (end_trim && end_trim <= au->i_nb_samples)
+        if (end_trim && (uint16_t) end_trim <= au->i_nb_samples)
             au->i_length = end_trim; /* Blatant abuse of the i_length field. */
         else
             au->i_length = 0;
@@ -2226,7 +2192,7 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes )
     else if( pid->u.p_pes->es.fmt.i_codec == VLC_CODEC_SUBT &&
              pid->u.p_pes->es.p_mpeg4desc )
     {
-        decoder_config_descriptor_t *dcd = &pid->u.p_pes->es.p_mpeg4desc->dec_descr;
+        const decoder_config_descriptor_t *dcd = &pid->u.p_pes->es.p_mpeg4desc->dec_descr;
 
         if( dcd->i_extra > 2 &&
             dcd->p_extra[0] == 0x10 &&
@@ -2340,15 +2306,17 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes )
             block_t *p_next = p_block->p_next;
             p_block->p_next = NULL;
 
-            if( p_pmt->pcr.i_first == -1 ) /* Not seen yet */
+            if( !p_pmt->pcr.b_fix_done ) /* Not seen yet */
                 PCRFixHandle( p_demux, p_pmt, p_block );
 
-            if( p_pmt->pcr.i_current > -1 || p_pmt->pcr.b_disable )
+            if( pid->u.p_pes->es.id && (p_pmt->pcr.i_current > -1 || p_pmt->pcr.b_disable) )
             {
                 if( pid->u.p_pes->p_prepcr_outqueue )
                 {
                     block_ChainAppend( &pid->u.p_pes->p_prepcr_outqueue, p_block );
                     p_block = pid->u.p_pes->p_prepcr_outqueue;
+                    p_next = p_block->p_next;
+                    p_block->p_next = NULL;
                     pid->u.p_pes->p_prepcr_outqueue = NULL;
                 }
 
@@ -2392,7 +2360,7 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes )
             }
             else
             {
-                if( p_pmt->pcr.i_first == -1 ) /* Not seen yet */
+                if( !p_pmt->pcr.b_fix_done ) /* Not seen yet */
                     PCRFixHandle( p_demux, p_pmt, p_block );
 
                 block_ChainAppend( &pid->u.p_pes->p_prepcr_outqueue, p_block );
@@ -2516,11 +2484,12 @@ static block_t* ReadTSPacket( demux_t *p_demux )
         for( ;; )
         {
             const uint8_t *p_peek;
-            int i_peek, i_skip = 0;
+            int i_peek = 0;
+            unsigned i_skip = 0;
 
             i_peek = stream_Peek( p_sys->stream, &p_peek,
                     p_sys->i_packet_size * 10 );
-            if( i_peek < p_sys->i_packet_size + 1 )
+            if( i_peek < 0 || (unsigned)i_peek < p_sys->i_packet_size + 1 )
             {
                 msg_Dbg( p_demux, "eof ?" );
                 return NULL;
@@ -2619,7 +2588,7 @@ static void ReadyQueuesPostSeek( demux_t *p_demux )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
 
-    ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+    ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
     for( int i=0; i< p_pat->programs.i_size; i++ )
     {
         ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
@@ -2630,7 +2599,7 @@ static void ReadyQueuesPostSeek( demux_t *p_demux )
             if( pid->type != TYPE_PES )
                 continue;
 
-            if( !pid->u.p_pes->es.id )
+            if( pid->u.p_pes->es.id )
             {
                 block_t *p_block = block_Alloc(1);
                 if( p_block )
@@ -2699,8 +2668,8 @@ static int SeekToTime( demux_t *p_demux, ts_pmt_t *p_pmt, int64_t i_scaledtime )
                 i_pos = stream_Tell( p_sys->stream );
 
             int i_pid = PIDGet( p_pkt );
-            if( i_pid != 0x1FFF && p_sys->pid[i_pid].type == TYPE_PES &&
-                p_sys->pid[i_pid].p_parent->u.p_pmt == p_pmt &&
+            if( i_pid != 0x1FFF && PID(p_sys, i_pid)->type == TYPE_PES &&
+                PID(p_sys, i_pid)->p_parent->u.p_pmt == p_pmt &&
                (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */
                (p_pkt->p_buffer[3] & 0xD0) == 0x10    /* Has payload but is not encrypted */
             )
@@ -2754,12 +2723,62 @@ static int SeekToTime( demux_t *p_demux, ts_pmt_t *p_pmt, int64_t i_scaledtime )
     return VLC_SUCCESS;
 }
 
+static ts_pid_t *PID( demux_sys_t *p_sys, uint16_t i_pid )
+{
+    switch( i_pid )
+    {
+        case 0:
+            return &p_sys->pids.pat;
+        case 0x1FFF:
+            return &p_sys->pids.dummy;
+        default:
+            if( p_sys->pids.i_last_pid == i_pid )
+                return p_sys->pids.p_last;
+        break;
+    }
+
+    for( int i=0; i < p_sys->pids.i_all; i++ )
+    {
+        if( p_sys->pids.pp_all[i]->i_pid == i_pid )
+        {
+            p_sys->pids.p_last = p_sys->pids.pp_all[i];
+            p_sys->pids.i_last_pid = i_pid;
+            return p_sys->pids.p_last;
+        }
+    }
+
+    if( p_sys->pids.i_all >= p_sys->pids.i_all_alloc )
+    {
+        ts_pid_t **p_realloc = realloc( p_sys->pids.pp_all,
+                                       (p_sys->pids.i_all_alloc + PID_ALLOC_CHUNK) * sizeof(ts_pid_t *) );
+        if( !p_realloc )
+            return NULL;
+        p_sys->pids.pp_all = p_realloc;
+        p_sys->pids.i_all_alloc += PID_ALLOC_CHUNK;
+    }
+
+    ts_pid_t *p_pid = calloc( 1, sizeof(*p_pid) );
+    if( !p_pid )
+    {
+        abort();
+        //return NULL;
+    }
+
+    p_pid->i_pid = i_pid;
+    p_sys->pids.pp_all[p_sys->pids.i_all++] = p_pid;
+
+    p_sys->pids.p_last = p_pid;
+    p_sys->pids.i_last_pid = i_pid;
+
+    return p_pid;
+}
+
 static ts_pmt_t * GetProgramByID( demux_sys_t *p_sys, int i_program )
 {
-    if(unlikely(p_sys->pid[0].type != TYPE_PAT))
+    if(unlikely(PID(p_sys, 0)->type != TYPE_PAT))
         return NULL;
 
-    ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+    ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
     for( int i = 0; i < p_pat->programs.i_size; i++ )
     {
         assert(p_pat->programs.p_elems[i]->type == TYPE_PMT);
@@ -2777,35 +2796,41 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_
     demux_sys_t *p_sys = p_demux->p_sys;
     int i_count = 0;
     block_t *p_pkt = NULL;
-    *pi_pcr = -1;
 
     for( ;; )
     {
+        *pi_pcr = -1;
+
         if( i_count++ > PROBE_CHUNK_COUNT || !( p_pkt = ReadTSPacket( p_demux ) ) )
         {
             break;
         }
 
-        int i_pid = PIDGet( p_pkt );
-        p_sys->pid[i_pid].i_flags |= FLAG_SEEN;
+        const int i_pid = PIDGet( p_pkt );
+        ts_pid_t *p_pid = PID(p_sys, i_pid);
+
+        p_pid->i_flags |= FLAG_SEEN;
 
-        if( i_pid != 0x1FFF && p_sys->pid[i_pid].type == TYPE_PES &&
-           (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */
-           (p_pkt->p_buffer[3] & 0xD0) == 0x10    /* Has payload but is not encrypted */
-          )
+        if( i_pid != 0x1FFF && (p_pkt->p_buffer[1] & 0x80) == 0 ) /* not corrupt */
         {
             bool b_pcrresult = true;
+            bool b_adaptfield = p_pkt->p_buffer[3] & 0x20;
 
-            if( p_pkt->i_buffer >= 4 + 2 + 5 )
+            if( b_adaptfield && p_pkt->i_buffer >= 4 + 2 + 5 )
                 *pi_pcr = GetPCR( p_pkt );
 
-            if( *pi_pcr == -1 )
+            if( *pi_pcr == -1 &&
+                (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* payload start */
+                (p_pkt->p_buffer[3] & 0xD0) == 0x10 && /* Has payload but is not encrypted */
+                p_pid->type == TYPE_PES &&
+                p_pid->u.p_pes->es.fmt.i_cat != UNKNOWN_ES
+              )
             {
                 b_pcrresult = false;
                 mtime_t i_dts = -1;
                 mtime_t i_pts = -1;
                 unsigned i_skip = 4;
-                if ( p_pkt->p_buffer[3] & 0x20 ) // adaptation field
+                if ( b_adaptfield ) // adaptation field
                     i_skip += 1 + p_pkt->p_buffer[4];
 
                 if ( VLC_SUCCESS == ParsePESHeader( p_demux, &p_pkt->p_buffer[i_skip],
@@ -2819,27 +2844,32 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_
                 }
             }
 
-            if( *pi_pcr != -1 ) // TODO: non ES PCR
+            if( *pi_pcr != -1 )
             {
-                ts_pid_t *pmtpid = p_sys->pid[i_pid].p_parent;
-                assert(pmtpid->type == TYPE_PMT);
-
-                if( i_program == 0 || i_program == pmtpid->u.p_pmt->i_number )
+                ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
+                for( int i=0; i<p_pat->programs.i_size; i++ )
                 {
-                    if( b_end )
-                    {
-                        pmtpid->u.p_pmt->i_last_dts = *pi_pcr;
-                    }
-                    /* Start, only keep first */
-                    else if( b_pcrresult && pmtpid->u.p_pmt->pcr.i_first == -1 )
-                    {
-                        pmtpid->u.p_pmt->pcr.i_first = *pi_pcr;
-                    }
-                    else if( pmtpid->u.p_pmt->pcr.i_first_dts < VLC_TS_0 )
+                    ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
+                    if( ( p_pmt->i_pid_pcr == p_pid->i_pid ||
+                        ( p_pmt->i_pid_pcr == 0x1FFF && p_pid->p_parent == p_pat->programs.p_elems[i] ) ) )
                     {
-                        pmtpid->u.p_pmt->pcr.i_first_dts = VLC_TS_0 + *pi_pcr * 100 / 9;
+                        if( b_end )
+                        {
+                            p_pmt->i_last_dts = *pi_pcr;
+                        }
+                        /* Start, only keep first */
+                        else if( b_pcrresult && p_pmt->pcr.i_first == -1 )
+                        {
+                            p_pmt->pcr.i_first = *pi_pcr;
+                        }
+                        else if( p_pmt->pcr.i_first_dts < VLC_TS_0 )
+                        {
+                            p_pmt->pcr.i_first_dts = FROM_SCALE(*pi_pcr);
+                        }
+
+                        if( i_program == 0 || i_program == p_pmt->i_number )
+                            *pb_found = true;
                     }
-                    *pb_found = true;
                 }
             }
         }
@@ -2916,11 +2946,11 @@ static void ProgramSetPCR( demux_t *p_demux, ts_pmt_t *p_pmt, mtime_t i_pcr )
 
     /* Check if we have enqueued blocks waiting the/before the
        PCR barrier, and then adapt pcr so they have valid PCR when dequeuing */
-    if( p_pmt->pcr.i_current == -1 )
+    if( p_pmt->pcr.i_current == -1 && p_pmt->pcr.b_fix_done )
     {
         mtime_t i_mindts = -1;
 
-        ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+        ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
         for( int i=0; i< p_pat->programs.i_size; i++ )
         {
             ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
@@ -2970,11 +3000,11 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
 
     pid->probed.i_pcr_count++;
 
-    if(unlikely(p_sys->pid[0].type != TYPE_PAT))
+    if(unlikely(PID(p_sys, 0)->type != TYPE_PAT))
         return;
 
     /* Search program and set the PCR */
-    ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+    ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
     for( int i = 0; i < p_pat->programs.i_size; i++ )
     {
         ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
@@ -2982,16 +3012,11 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
 
         if( p_pmt->i_pid_pcr == 0x1FFF ) /* That program has no dedicated PCR pid ISO/IEC 13818-1 2.4.4.9 */
         {
-            if( pid->p_parent ) /* PCR shall be on pid itself */
+            if( pid->p_parent == p_pat->programs.p_elems[i] ) /* PCR shall be on pid itself */
             {
                 /* ? update PCR for the whole group program ? */
                 ProgramSetPCR( p_demux, p_pmt, i_program_pcr );
             }
-            else
-            {
-                msg_Warn(p_demux, "discarding PCR update from pid %d which has no owner", pid->i_pid);
-            }
-            break;
         }
         else /* set PCR provided by current pid to program(s) referencing it */
         {
@@ -3014,7 +3039,7 @@ static int FindPCRCandidate( ts_pmt_t *p_pmt )
     for( int i=0; i<p_pmt->e_streams.i_size; i++ )
     {
         ts_pid_t *p_pid = p_pmt->e_streams.p_elems[i];
-        if( SEEN(*p_pid) &&
+        if( SEEN(p_pid) &&
             (!p_cand || p_cand->i_pid != i_previous) )
         {
             if( p_pid->probed.i_pcr_count ) /* check PCR frequency first */
@@ -3045,23 +3070,29 @@ static int FindPCRCandidate( ts_pmt_t *p_pmt )
         return 0x1FFF;
 }
 
+/* Tries to reselect a new PCR when none has been received */
 static void PCRFixHandle( demux_t *p_demux, ts_pmt_t *p_pmt, block_t *p_block )
 {
-    if( p_pmt->pcr.i_first > -1 || p_pmt->pcr.b_disable )
+    if ( p_pmt->pcr.b_disable || p_pmt->pcr.b_fix_done )
+    {
         return;
-
+    }
     /* Record the first data packet timestamp in case there wont be any PCR */
-    if( !p_pmt->pcr.i_first_dts )
+    else if( !p_pmt->pcr.i_first_dts )
     {
         p_pmt->pcr.i_first_dts = p_block->i_dts;
     }
-    else if( p_block->i_dts - p_pmt->pcr.i_first_dts > CLOCK_FREQ / 2 ) /* "shall not exceed 100ms" */
+    else if( p_block->i_dts - p_pmt->pcr.i_first_dts > CLOCK_FREQ / 2 ) /* "PCR repeat rate shall not exceed 100ms" */
     {
-        int i_cand = FindPCRCandidate( p_pmt );
-        p_pmt->i_pid_pcr = i_cand;
-        p_pmt->pcr.b_disable = true; /* So we do not wait packet PCR flag as there might be none on the pid */
-        msg_Warn( p_demux, "No PCR received for program %d, set up workaround using pid %d",
-                  p_pmt->i_number, i_cand );
+        if( p_pmt->pcr.i_current < 0 )
+        {
+            int i_cand = FindPCRCandidate( p_pmt );
+            p_pmt->i_pid_pcr = i_cand;
+            msg_Warn( p_demux, "No PCR received for program %d, set up workaround using pid %d",
+                      p_pmt->i_number, i_cand );
+            UpdatePESFilters( p_demux, p_demux->p_sys->b_es_all );
+            p_pmt->pcr.b_fix_done = true;
+        }
     }
 }
 
@@ -3168,7 +3199,7 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
 
     PCRHandle( p_demux, pid, p_bk );
 
-    if( i_skip >= 188 || pid->u.p_pes->es.id == NULL )
+    if( i_skip >= 188 )
     {
         block_Release( p_bk );
         return i_ret;
@@ -3325,227 +3356,6 @@ static void PIDFillFormat( es_format_t *fmt, int i_stream_type )
     fmt->b_packetized = false;
 }
 
-/*****************************************************************************
- * MP4 specific functions (IOD parser)
- *****************************************************************************/
-static int  IODDescriptorLength( int *pi_data, uint8_t **pp_data )
-{
-    unsigned int i_b;
-    unsigned int i_len = 0;
-    do
-    {
-        i_b = **pp_data;
-        (*pp_data)++;
-        (*pi_data)--;
-        i_len = ( i_len << 7 ) + ( i_b&0x7f );
-
-    } while( i_b&0x80 && *pi_data > 0 );
-
-    if (i_len > *pi_data)
-        i_len = *pi_data;
-
-    return i_len;
-}
-
-static int IODGetBytes( int *pi_data, uint8_t **pp_data, size_t bytes )
-{
-    uint32_t res = 0;
-    while( *pi_data > 0 && bytes-- )
-    {
-        res <<= 8;
-        res |= **pp_data;
-        (*pp_data)++;
-        (*pi_data)--;
-    }
-
-    return res;
-}
-
-static char* IODGetURL( int *pi_data, uint8_t **pp_data )
-{
-    int len = IODGetBytes( pi_data, pp_data, 1 );
-    if (len > *pi_data)
-        len = *pi_data;
-    char *url = strndup( (char*)*pp_data, len );
-    *pp_data += len;
-    *pi_data -= len;
-    return url;
-}
-
-static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data )
-{
-    uint8_t i_iod_tag, i_iod_label, byte1, byte2, byte3;
-
-    iod_descriptor_t *p_iod = calloc( 1, sizeof( iod_descriptor_t ) );
-    if( !p_iod )
-        return NULL;
-
-    if( i_data < 3 )
-    {
-        return p_iod;
-    }
-
-    byte1 = IODGetBytes( &i_data, &p_data, 1 );
-    byte2 = IODGetBytes( &i_data, &p_data, 1 );
-    byte3 = IODGetBytes( &i_data, &p_data, 1 );
-    if( byte2 == 0x02 ) //old vlc's buggy implementation of the IOD_descriptor
-    {
-        i_iod_label = byte1;
-        i_iod_tag = byte2;
-    }
-    else  //correct implementation of the IOD_descriptor
-    {
-        i_iod_label = byte2;
-        i_iod_tag = byte3;
-    }
-
-    ts_debug( "\n* iod label:%d tag:0x%x", i_iod_label, i_iod_tag );
-
-    if( i_iod_tag != 0x02 )
-    {
-        ts_debug( "\n ERR: tag %02x != 0x02", i_iod_tag );
-        return p_iod;
-    }
-
-    IODDescriptorLength( &i_data, &p_data );
-
-    uint16_t i_od_id = ( IODGetBytes( &i_data, &p_data, 1 ) << 2 );
-    uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
-    i_od_id |= i_flags >> 6;
-    ts_debug( "\n* od_id:%d", i_od_id );
-    ts_debug( "\n* includeInlineProfileLevel flag:%d", ( i_flags >> 4 )&0x01 );
-    if ((i_flags >> 5) & 0x01)
-    {
-        p_iod->psz_url = IODGetURL( &i_data, &p_data );
-        ts_debug( "\n* url string:%s", p_iod->psz_url );
-        ts_debug( "\n*****************************\n" );
-        return p_iod;
-    }
-    else
-    {
-        p_iod->psz_url = NULL;
-    }
-
-    /* Profile Level Indication */
-    IODGetBytes( &i_data, &p_data, 1 ); /* OD */
-    IODGetBytes( &i_data, &p_data, 1 ); /* scene */
-    IODGetBytes( &i_data, &p_data, 1 ); /* audio */
-    IODGetBytes( &i_data, &p_data, 1 ); /* visual */
-    IODGetBytes( &i_data, &p_data, 1 ); /* graphics */
-
-    int i_length = 0;
-    int i_data_sav = i_data;
-    uint8_t *p_data_sav = p_data;
-    for (int i = 0; i_data > 0 && i < ES_DESCRIPTOR_COUNT; i++)
-    {
-        es_mpeg4_descriptor_t *es_descr = &p_iod->es_descr[i];
-
-        p_data = p_data_sav + i_length;
-        i_data = i_data_sav - i_length;
-
-        int i_tag = IODGetBytes( &i_data, &p_data, 1 );
-        i_length = IODDescriptorLength( &i_data, &p_data );
-
-        i_data_sav = i_data;
-        p_data_sav = p_data;
-
-        i_data = i_length;
-
-        if ( i_tag != 0x03 )
-        {
-            ts_debug( "\n* - OD tag:0x%x Unsupported", i_tag );
-            continue;
-        }
-
-        es_descr->i_es_id = IODGetBytes( &i_data, &p_data, 2 );
-        int i_flags = IODGetBytes( &i_data, &p_data, 1 );
-        bool b_streamDependenceFlag = ( i_flags >> 7 )&0x01;
-        if( b_streamDependenceFlag )
-            IODGetBytes( &i_data, &p_data, 2 ); /* dependOn_es_id */
-
-        if( (i_flags >> 6) & 0x01 )
-            es_descr->psz_url = IODGetURL( &i_data, &p_data );
-
-        bool b_OCRStreamFlag = ( i_flags >> 5 )&0x01;
-        if( b_OCRStreamFlag )
-            IODGetBytes( &i_data, &p_data, 2 ); /* OCR_es_id */
-
-        if( IODGetBytes( &i_data, &p_data, 1 ) != 0x04 )
-        {
-            ts_debug( "\n* ERR missing DecoderConfigDescr" );
-            continue;
-        }
-        int i_config_desc_length = IODDescriptorLength( &i_data, &p_data ); /* DecoderConfigDescr_length */
-        decoder_config_descriptor_t *dec_descr = &es_descr->dec_descr;
-        dec_descr->i_objectTypeIndication = IODGetBytes( &i_data, &p_data, 1 );
-        i_flags = IODGetBytes( &i_data, &p_data, 1 );
-        dec_descr->i_streamType = i_flags >> 2;
-
-        IODGetBytes( &i_data, &p_data, 3); /* bufferSizeDB */
-        IODGetBytes( &i_data, &p_data, 4); /* maxBitrate */
-        IODGetBytes( &i_data, &p_data, 4 ); /* avgBitrate */
-
-        if( i_config_desc_length > 13 && IODGetBytes( &i_data, &p_data, 1 ) == 0x05 )
-        {
-            dec_descr->i_extra = IODDescriptorLength( &i_data, &p_data );
-            if( dec_descr->i_extra > 0 )
-            {
-                dec_descr->p_extra = xmalloc( dec_descr->i_extra );
-                memcpy(dec_descr->p_extra, p_data, dec_descr->i_extra);
-                p_data += dec_descr->i_extra;
-                i_data -= dec_descr->i_extra;
-            }
-        }
-        else
-        {
-            dec_descr->i_extra = 0;
-            dec_descr->p_extra = NULL;
-        }
-
-        if( IODGetBytes( &i_data, &p_data, 1 ) != 0x06 )
-        {
-            ts_debug( "\n* ERR missing SLConfigDescr" );
-            continue;
-        }
-        IODDescriptorLength( &i_data, &p_data ); /* SLConfigDescr_length */
-        switch( IODGetBytes( &i_data, &p_data, 1 ) /* predefined */ )
-        {
-        default:
-            ts_debug( "\n* ERR unsupported SLConfigDescr predefined" );
-        case 0x01:
-            // FIXME
-            break;
-        }
-        es_descr->b_ok = true;
-    }
-
-    return p_iod;
-}
-
-static void IODFree( iod_descriptor_t *p_iod )
-{
-    if( p_iod->psz_url )
-    {
-        free( p_iod->psz_url );
-        free( p_iod );
-        return;
-    }
-
-    for( int i = 0; i < 255; i++ )
-    {
-#define es_descr p_iod->es_descr[i]
-        if( es_descr.b_ok )
-        {
-            if( es_descr.psz_url )
-                free( es_descr.psz_url );
-            else
-                free( es_descr.dec_descr.p_extra );
-        }
-#undef  es_descr
-    }
-    free( p_iod );
-}
-
 /****************************************************************************
  ****************************************************************************
  ** libdvbpsi callbacks
@@ -3572,9 +3382,9 @@ static void ValidateDVBMeta( demux_t *p_demux, int i_pid )
     /* This doesn't look like a DVB stream so don't try
      * parsing the SDT/EDT/TDT */
 
-    PIDRelease( p_demux, &p_sys->pid[0x11] );
-    PIDRelease( p_demux, &p_sys->pid[0x12] );
-    PIDRelease( p_demux, &p_sys->pid[0x14] );
+    PIDRelease( p_demux, PID(p_sys, 0x11) );
+    PIDRelease( p_demux, PID(p_sys, 0x12) );
+    PIDRelease( p_demux, PID(p_sys, 0x14) );
     p_sys->b_dvb_meta = false;
 }
 
@@ -3630,7 +3440,7 @@ static char *EITConvertToUTF8( demux_t *p_demux,
 static void SDTCallBack( demux_t *p_demux, dvbpsi_sdt_t *p_sdt )
 {
     demux_sys_t          *p_sys = p_demux->p_sys;
-    ts_pid_t             *sdt = &p_sys->pid[0x11];
+    ts_pid_t             *sdt = PID(p_sys, 0x11);
     dvbpsi_sdt_service_t *p_srv;
 
     msg_Dbg( p_demux, "SDTCallBack called" );
@@ -4065,7 +3875,7 @@ static void PSINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id,
     msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
              i_table_id, i_table_id, i_extension, i_extension );
 #endif
-    if( p_sys->pid[0].u.p_pat->i_version != -1 && i_table_id == 0x42 )
+    if( PID(p_sys, 0)->u.p_pat->i_version != -1 && i_table_id == 0x42 )
     {
         msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
                  i_table_id, i_table_id, i_extension, i_extension );
@@ -4073,7 +3883,7 @@ static void PSINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id,
         if( !dvbpsi_sdt_attach( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_demux ) )
             msg_Err( p_demux, "PSINewTableCallback: failed attaching SDTCallback" );
     }
-    else if( p_sys->pid[0x11].u.p_psi->i_version != -1 &&
+    else if( PID(p_sys, 0x11)->u.p_psi->i_version != -1 &&
              ( i_table_id == 0x4e || /* Current/Following */
                (i_table_id >= 0x50 && i_table_id <= 0x5f) ) ) /* Schedule */
     {
@@ -4087,7 +3897,7 @@ static void PSINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id,
         if( !dvbpsi_eit_attach( h, i_table_id, i_extension, cb, p_demux ) )
             msg_Err( p_demux, "PSINewTableCallback: failed attaching EITCallback" );
     }
-    else if( p_demux->p_sys->pid[0x11].u.p_psi->i_version != -1 &&
+    else if( PID(p_sys, 0x11)->u.p_psi->i_version != -1 &&
             (i_table_id == 0x70 /* TDT */ || i_table_id == 0x73 /* TOT */) )
     {
          msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
@@ -4140,35 +3950,75 @@ static bool PMTEsHasComponentTag( const dvbpsi_pmt_es_t *p_es,
     return p_si->i_component_tag == i_component_tag;
 }
 
+static const es_mpeg4_descriptor_t * GetMPEG4DescByEsId( const iod_descriptor_t *iod,
+                                                         uint16_t i_es_id )
+{
+    if( iod )
+    for( int i = 0; i < ES_DESCRIPTOR_COUNT; i++ )
+    {
+        if( iod->es_descr[i].i_es_id == i_es_id )
+        {
+            if ( iod->es_descr[i].b_ok )
+                return &iod->es_descr[i];
+        }
+    }
+    return NULL;
+}
+
 static void PMTSetupEsISO14496( demux_t *p_demux, ts_pes_es_t *p_es,
                                 const ts_pmt_t *p_pmt, const dvbpsi_pmt_es_t *p_dvbpsies )
 {
     es_format_t *p_fmt = &p_es->fmt;
 
-    /* MPEG-4 stream: search FMC_DESCRIPTOR (SL Packetized stream) */
-    dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_dvbpsies, 0x1f );
-
-    if( p_dr && p_dr->i_length == 2 )
+    const dvbpsi_descriptor_t *p_dr = p_dvbpsies->p_first_descriptor;
+    while( p_dr )
     {
-        const int i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
+        const es_mpeg4_descriptor_t *p_esdescr = NULL;
+        uint16_t i_es_id;
+        uint8_t i_length = p_dr->i_length;
 
-        msg_Dbg( p_demux, "found FMC_descriptor declaring sl packetization on es_id=%d", i_es_id );
-
-        p_es->p_mpeg4desc = NULL;
+        switch( p_dr->i_tag )
+        {
+            case 0x1f: /* FMC Descriptor */
+                while( i_length >= 3 && !p_esdescr )
+                {
+                    i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
+                    p_esdescr = GetMPEG4DescByEsId( p_pmt->iod, i_es_id );
+                    /* FIXME: add flexmux channel */
+                    i_length -= 3;
+                    if( p_esdescr )
+                        msg_Dbg( p_demux, "found FMC_descriptor declaring sl packetization on es_id=%"PRIu16, i_es_id );
+                }
+                break;
+            case 0x1e: /* SL Descriptor */
+                if( i_length == 2 )
+                {
+                    i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
+                    p_esdescr = GetMPEG4DescByEsId( p_pmt->iod, i_es_id );
+                    if( p_esdescr )
+                        msg_Dbg( p_demux, "found SL_descriptor declaring sl packetization on es_id=%"PRIu16, i_es_id );
+                }
+                break;
+            default:
+                break;
+        }
 
-        for( int i = 0; i < ES_DESCRIPTOR_COUNT; i++ )
+        if( p_esdescr )
         {
-            iod_descriptor_t *iod = p_pmt->iod;
-            if( iod->es_descr[i].i_es_id == i_es_id )
+            if( !p_esdescr->b_ok )
             {
-                if ( iod->es_descr[i].b_ok )
-                    p_es->p_mpeg4desc = &iod->es_descr[i];
-                else
-                    msg_Dbg( p_demux, "MPEG-4 descriptor not yet available on es_id=%d", i_es_id );
+                msg_Dbg( p_demux, "MPEG-4 descriptor not yet available on es_id=%"PRIu16, i_es_id );
+            }
+            else
+            {
+                p_es->p_mpeg4desc = p_esdescr;
                 break;
             }
         }
+
+        p_dr = p_dr->p_next;
     }
+
     if( !p_es->p_mpeg4desc )
     {
         switch( p_dvbpsies->i_type )
@@ -4254,7 +4104,7 @@ static void PMTSetupEsISO14496( demux_t *p_demux, ts_pes_es_t *p_es,
 
     if( p_fmt->i_cat != UNKNOWN_ES )
     {
-        p_fmt->i_extra = dcd->i_extra;
+        p_fmt->i_extra = __MIN(dcd->i_extra, INT32_MAX);
         if( p_fmt->i_extra > 0 )
         {
             p_fmt->p_extra = malloc( p_fmt->i_extra );
@@ -4382,7 +4232,7 @@ static void PMTSetupEsTeletext( demux_t *p_demux, ts_pes_t *p_pes,
             }
             else
             {
-                p_page_es = malloc( sizeof(*p_page_es) );
+                p_page_es = calloc( 1, sizeof(*p_page_es) );
                 if( !p_page_es )
                     break;
 
@@ -5010,6 +4860,14 @@ static void PMTParseEsIso639( demux_t *p_demux, ts_pes_es_t *p_es,
 #endif
 }
 
+static inline void SetExtraESGroupAndID( demux_sys_t *p_sys, es_format_t *p_fmt,
+                                         const es_format_t *p_parent_fmt )
+{
+    if ( p_sys->b_es_id_pid ) /* pid is 13 bits */
+        p_fmt->i_id = (p_sys->i_next_extraid++ << 13) | p_parent_fmt->i_id;
+    p_fmt->i_group = p_parent_fmt->i_group;
+}
+
 static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delayed )
 {
     demux_sys_t  *p_sys = p_demux->p_sys;
@@ -5019,11 +4877,13 @@ static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delay
 
     if( pid && p_sys->es_creation == CREATE_ES )
     {
+        /* FIXME: other owners / shared pid */
         pid->u.p_pes->es.id = es_out_Add( p_demux->out, &pid->u.p_pes->es.fmt );
         for( int i = 0; i < pid->u.p_pes->extra_es.i_size; i++ )
         {
-            pid->u.p_pes->extra_es.p_elems[i]->id =
-                    es_out_Add( p_demux->out, &pid->u.p_pes->extra_es.p_elems[i]->fmt );
+            es_format_t *p_fmt = &pid->u.p_pes->extra_es.p_elems[i]->fmt;
+            SetExtraESGroupAndID( p_sys, p_fmt, &pid->u.p_pes->es.fmt );
+            pid->u.p_pes->extra_es.p_elems[i]->id = es_out_Add( p_demux->out, p_fmt );
         }
         p_sys->i_pmt_es += 1 + pid->u.p_pes->extra_es.i_size;
 
@@ -5040,7 +4900,7 @@ static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delay
 
     if( b_create_delayed )
     {
-        ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+        ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
         for( int i=0; i< p_pat->programs.i_size; i++ )
         {
             ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
@@ -5053,8 +4913,9 @@ static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delay
                 pid->u.p_pes->es.id = es_out_Add( p_demux->out, &pid->u.p_pes->es.fmt );
                 for( int k = 0; k < pid->u.p_pes->extra_es.i_size; k++ )
                 {
-                    pid->u.p_pes->extra_es.p_elems[k]->id =
-                        es_out_Add( p_demux->out, &pid->u.p_pes->extra_es.p_elems[k]->fmt );
+                    es_format_t *p_fmt = &pid->u.p_pes->extra_es.p_elems[k]->fmt;
+                    SetExtraESGroupAndID( p_sys, p_fmt, &pid->u.p_pes->es.fmt );
+                    pid->u.p_pes->extra_es.p_elems[k]->id = es_out_Add( p_demux->out, p_fmt );
                 }
                 p_sys->i_pmt_es += 1 + pid->u.p_pes->extra_es.i_size;
             }
@@ -5074,13 +4935,13 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
 
     msg_Dbg( p_demux, "PMTCallBack called" );
 
-    if (unlikely(p_sys->pid[0].type != TYPE_PAT))
+    if (unlikely(PID(p_sys, 0)->type != TYPE_PAT))
     {
-        assert(p_sys->pid[0].type == TYPE_PAT);
+        assert(PID(p_sys, 0)->type == TYPE_PAT);
         dvbpsi_pmt_delete(p_dvbpsipmt);
     }
 
-    const ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
+    const ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat;
 
     /* First find this PMT declared in PAT */
     for( int i = 0; !pmtpid && i < p_pat->programs.i_size; i++ )
@@ -5122,6 +4983,8 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
     {
         IODFree( p_pmt->iod );
         p_pmt->iod = NULL;
+        for( int i=0; i<old_es_rm.i_size; i++ )
+            old_es_rm.p_elems[i]->u.p_pes->es.p_mpeg4desc = NULL;
     }
 
     msg_Dbg( p_demux, "new PMT program number=%d version=%d pid_pcr=%d",
@@ -5132,7 +4995,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
     ValidateDVBMeta( p_demux, p_pmt->i_pid_pcr );
 
     if( ProgramIsSelected( p_sys, p_pmt->i_number ) )
-        SetPIDFilter( p_sys, &p_sys->pid[p_pmt->i_pid_pcr], true ); /* Set demux filter */
+        SetPIDFilter( p_sys, PID(p_sys, p_pmt->i_pid_pcr), true ); /* Set demux filter */
 
     /* Parse PMT descriptors */
     ts_pmt_registration_type_t registration_type = TS_PMT_REGISTRATION_NONE;
@@ -5173,7 +5036,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
         {
         case 0x1d: /* We have found an IOD descriptor */
             msg_Dbg( p_demux, " * PMT descriptor : IOD (0x1d)" );
-            p_pmt->iod = IODNew( p_dr->i_length, p_dr->p_data );
+            p_pmt->iod = IODNew( VLC_OBJECT(p_demux), p_dr->i_length, p_dr->p_data );
             break;
 
         case 0x9:
@@ -5218,7 +5081,12 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
         bool b_reusing_pid = false;
         ts_pes_t *p_pes;
 
-        ts_pid_t *pespid = &p_sys->pid[p_dvbpsies->i_pid];
+        ts_pid_t *pespid = PID(p_sys, p_dvbpsies->i_pid);
+        if ( pespid->type == TYPE_PES && pespid->p_parent->u.p_pmt->i_number != p_pmt->i_number )
+        {
+            msg_Warn( p_demux, " * PMT wants to get a share or pid %d (unsupported)", pespid->i_pid );
+            continue;
+        }
 
         /* Find out if the PID was already declared */
         for( int i = 0; i < old_es_rm.i_size; i++ )
@@ -5320,7 +5188,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
 
         PIDFillFormat( &p_pes->es.fmt, p_dvbpsies->i_type );
 
-        pespid->i_flags |= SEEN(p_sys->pid[p_dvbpsies->i_pid]);
+        pespid->i_flags |= SEEN(PID(p_sys, p_dvbpsies->i_pid));
 
         bool b_registration_applied = false;
         if ( p_dvbpsies->i_type >= 0x80 ) /* non standard, extensions */
@@ -5389,9 +5257,10 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
             break;
         }
 
+        /* Set Groups / ID */
         p_pes->es.fmt.i_group = p_dvbpsipmt->i_program_number;
-        for( int i = 0; i < p_pes->extra_es.i_size; i++ )
-            p_pes->extra_es.p_elems[i]->fmt.i_group = p_dvbpsipmt->i_program_number;
+        if( p_sys->b_es_id_pid )
+            p_pes->es.fmt.i_id = p_dvbpsies->i_pid;
 
         if( p_pes->es.fmt.i_cat == UNKNOWN_ES )
         {
@@ -5404,8 +5273,6 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
             msg_Dbg( p_demux, "   => pid %d has now es fcc=%4.4s",
                      p_dvbpsies->i_pid, (char*)&p_pes->es.fmt.i_codec );
 
-            if( p_sys->b_es_id_pid ) p_pes->es.fmt.i_id = p_dvbpsies->i_pid;
-
             /* Check if we can avoid restarting the ES */
             if( b_reusing_pid )
             {
@@ -5473,7 +5340,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
     else if( stream_Control( p_sys->stream, STREAM_SET_PRIVATE_ID_CA,
                              p_dvbpsipmt ) != VLC_SUCCESS )
     {
-        if ( p_sys->arib.e_mode == ARIBMODE_ENABLED )
+        if ( p_sys->arib.e_mode == ARIBMODE_ENABLED && !p_sys->arib.b25stream )
         {
             p_sys->arib.b25stream = stream_FilterNew( p_demux->s, "aribcam" );
             p_sys->stream = ( p_sys->arib.b25stream ) ? p_sys->arib.b25stream : p_demux->s;
@@ -5530,14 +5397,14 @@ static void PATCallBack( void *data, dvbpsi_pat_t *p_dvbpsipat )
     demux_t              *p_demux = data;
     demux_sys_t          *p_sys = p_demux->p_sys;
     dvbpsi_pat_program_t *p_program;
-    ts_pid_t             *patpid = &p_sys->pid[0];
-    ts_pat_t             *p_pat = p_sys->pid[0].u.p_pat;
+    ts_pid_t             *patpid = PID(p_sys, 0);
+    ts_pat_t             *p_pat = PID(p_sys, 0)->u.p_pat;
 
     patpid->i_flags |= FLAG_SEEN;
 
     msg_Dbg( p_demux, "PATCallBack called" );
 
-    if(unlikely( p_sys->pid[0].type != TYPE_PAT ))
+    if(unlikely( PID(p_sys, 0)->type != TYPE_PAT ))
     {
         msg_Warn( p_demux, "PATCallBack called on invalid pid" );
         return;
@@ -5572,7 +5439,7 @@ static void PATCallBack( void *data, dvbpsi_pat_t *p_dvbpsipat )
         if( p_program->i_number == 0 )
             continue;
 
-        ts_pid_t *pmtpid = &p_sys->pid[p_program->i_pid];
+        ts_pid_t *pmtpid = PID(p_sys, p_program->i_pid);
 
         ValidateDVBMeta( p_demux, p_program->i_pid );
 
@@ -5677,7 +5544,7 @@ static ts_pmt_t *ts_pmt_New( demux_t *p_demux )
 
     pmt->i_version  = -1;
     pmt->i_number   = -1;
-    pmt->i_pid_pcr  = -1;
+    pmt->i_pid_pcr  = 0x1FFF;
     pmt->iod        = NULL;
 
     pmt->i_last_dts = -1;
@@ -5688,6 +5555,8 @@ static ts_pmt_t *ts_pmt_New( demux_t *p_demux )
     pmt->pcr.i_first_dts = VLC_TS_INVALID;
     pmt->pcr.i_pcroffset = -1;
 
+    pmt->pcr.b_fix_done = false;
+
     return pmt;
 }
 
@@ -5742,7 +5611,6 @@ static void ts_pes_Del( demux_t *p_demux, ts_pes_t *pes )
         block_ChainRelease( pes->p_prepcr_outqueue );
 
     es_format_Clean( &pes->es.fmt );
-    free( pes->es.p_mpeg4desc );
 
     for( int i = 0; i < pes->extra_es.i_size; i++ )
     {