]> git.sesse.net Git - vlc/blobdiff - modules/demux/ts.c
demux: ts: reject unknown probed streams
[vlc] / modules / demux / ts.c
index 670bc7a76070486fc5eccc37baaf34fc9e7a2bed..a467b56561c5c2cc39ce074eb6aae1c73694c977 100644 (file)
@@ -62,6 +62,9 @@
 # include <dvbpsi/tot.h>
 
 #include "../mux/mpeg/dvbpsi_compat.h"
+#include "../mux/mpeg/streams.h"
+#include "../mux/mpeg/tsutil.h"
+#include "../mux/mpeg/tables.h"
 
 #include "../codec/opus_header.h"
 
@@ -303,6 +306,12 @@ typedef struct
     ts_es_t     **extra_es;
     int         i_extra_es;
 
+    struct
+    {
+        vlc_fourcc_t i_fourcc;
+        int i_type;
+        bool b_haspcr;
+    } probed;
 } ts_pid_t;
 
 typedef struct
@@ -310,6 +319,9 @@ typedef struct
     int i_service;
 } vdr_info_t;
 
+#define MIN_ES_PID 4    /* Should be 32.. broken muxers */
+#define MAX_ES_PID 8190
+
 struct demux_sys_t
 {
     stream_t   *stream;
@@ -352,6 +364,7 @@ struct demux_sys_t
     int         i_pmt;
     ts_pid_t    **pmt;
     int         i_pmt_es;
+    bool        b_delay_es_creation;
 
     /* */
     bool        b_es_id_pid;
@@ -383,6 +396,13 @@ struct demux_sys_t
         mtime_t     i_first_dts;
     } pcrfix;
 
+    struct
+    {
+        mtime_t i_first_dts;     /* first dts encountered for the stream */
+        int     i_timesourcepid; /* which pid we saved the dts from */
+        bool    b_pat_deadline;  /* set if we haven't seen PAT within 140ms */
+    } patfix;
+
     vdr_info_t  vdr;
 
     /* */
@@ -414,6 +434,7 @@ static inline int PIDGet( block_t *p )
 }
 
 static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
+static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid );
 
 static block_t* ReadTSPacket( demux_t *p_demux );
 static int Seek( demux_t *p_demux, double f_percent );
@@ -422,6 +443,7 @@ static void GetLastPCR( demux_t *p_demux );
 static void CheckPCR( demux_t *p_demux );
 static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
 static void PCRFixHandle( demux_t *, block_t * );
+static mtime_t AdjustPTSWrapAround( demux_t *, mtime_t );
 
 static void              IODFree( iod_descriptor_t * );
 
@@ -636,6 +658,279 @@ static inline mtime_t ExtractPESTimestamp( const uint8_t *p_data )
              (mtime_t)(p_data[4] >> 1);
 }
 
+static void ProbePES( demux_t *p_demux, ts_pid_t *pid, const uint8_t *p_pesstart, bool b_adaptfield )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    const uint8_t *p_pes = p_pesstart;
+    pid->probed.i_type = -1;
+
+    if( b_adaptfield )
+    {
+        uint8_t len = *p_pes;
+        p_pes++;
+
+        if(len == 0)
+        {
+            p_pes++; /* stuffing */
+        }
+        else
+        {
+            pid->probed.b_haspcr = ( *p_pes >= 7 && (p_pes[1] & 0x10) );
+            p_pes += len;
+        }
+    }
+
+    if( p_pes - p_pesstart >= TS_PACKET_SIZE_188 - 9)
+        return;
+
+    if( p_pes[0] != 0 || p_pes[1] != 0 || p_pes[2] != 1 )
+        return;
+
+    size_t i_pesextoffset = 8;
+    mtime_t i_dts = -1;
+    if( p_pes[7] & 0x80 ) // PTS
+    {
+        i_pesextoffset += 5;
+        i_dts = ExtractPESTimestamp( &p_pes[9] );
+    }
+    if( p_pes[7] & 0x40 ) // DTS
+    {
+        i_pesextoffset += 5;
+        i_dts = ExtractPESTimestamp( &p_pes[14] );
+    }
+    if( p_pes[7] & 0x20 ) // ESCR
+        i_pesextoffset += 6;
+    if( p_pes[7] & 0x10 ) // ESrate
+        i_pesextoffset += 3;
+    if( p_pes[7] & 0x08 ) // DSM
+        i_pesextoffset += 1;
+    if( p_pes[7] & 0x04 ) // CopyInfo
+        i_pesextoffset += 1;
+    if( p_pes[7] & 0x02 ) // PESCRC
+        i_pesextoffset += 2;
+
+     /* HeaderdataLength */
+    const size_t i_payloadoffset = 8 + 1 + p_pes[8];
+    i_pesextoffset += 1;
+
+    if( p_pes[7] & 0x01 ) // PESExt
+    {
+        size_t i_extension2_offset = 1;
+        if ( p_pes[i_pesextoffset] & 0x80 ) // private data
+            i_extension2_offset += 16;
+        if ( p_pes[i_pesextoffset] & 0x40 ) // pack
+            i_extension2_offset += 1;
+        if ( p_pes[i_pesextoffset] & 0x20 ) // seq
+            i_extension2_offset += 2;
+        if ( p_pes[i_pesextoffset] & 0x10 ) // P-STD
+            i_extension2_offset += 2;
+        if ( p_pes[i_pesextoffset] & 0x01 ) // Extension 2
+        {
+            uint8_t i_len = p_pes[i_pesextoffset + i_extension2_offset] & 0x7F;
+            i_extension2_offset += i_len;
+        }
+    }
+    /* (i_payloadoffset - i_pesextoffset) 0xFF stuffing */
+
+    if( &p_pes[i_payloadoffset] - p_pesstart >= TS_PACKET_SIZE_188 - 4)
+        return;
+
+    const uint8_t *p_data = &p_pes[i_payloadoffset];
+    /* AUDIO STREAM */
+    if(p_pes[3] >= 0xC0 && p_pes[3] <= 0xDF)
+    {
+        if( !memcmp( p_data, "\x7F\xFE\x80\x01", 4 ) )
+        {
+            pid->probed.i_type = 0x06;
+            pid->probed.i_fourcc = VLC_CODEC_DTS;
+        }
+        else if( !memcmp( p_data, "\x0B\x77", 2 ) )
+        {
+            pid->probed.i_type = 0x06;
+            pid->probed.i_fourcc = VLC_CODEC_EAC3;
+        }
+        else if( p_data[0] == 0xFF && (p_data[1] & 0xE0) == 0xE0 )
+        {
+            switch(p_data[1] & 18)
+            {
+            /* 10 - MPEG Version 2 (ISO/IEC 13818-3)
+               11 - MPEG Version 1 (ISO/IEC 11172-3) */
+                case 0x10:
+                    pid->probed.i_type = 0x04;
+                    break;
+                case 0x18:
+                    pid->probed.i_type = 0x03;
+                default:
+                    break;
+            }
+
+            switch(p_data[1] & 6)
+            {
+            /* 01 - Layer III
+               10 - Layer II
+               11 - Layer I */
+                case 0x06:
+                    pid->probed.i_type = 0x04;
+                    pid->probed.i_fourcc = VLC_CODEC_MPGA;
+                    break;
+                case 0x04:
+                    pid->probed.i_type = 0x04;
+                    pid->probed.i_fourcc = VLC_CODEC_MP2;
+                    break;
+                case 0x02:
+                    pid->probed.i_type = 0x04;
+                    pid->probed.i_fourcc = VLC_CODEC_MP3;
+                default:
+                    break;
+            }
+        }
+    }
+    /* VIDEO STREAM */
+    else if( p_pes[3] >= 0xE0 && p_pes[3] <= 0xEF )
+    {
+        if( !memcmp( p_data, "\x00\x00\x00", 4 ) )
+        {
+            pid->probed.i_type = 0x1b;
+            pid->probed.i_fourcc = VLC_CODEC_H264;
+        }
+        else if( !memcmp( p_data, "\x00\x00\x01", 4 ) )
+        {
+            pid->probed.i_type = 0x02;
+            pid->probed.i_fourcc = VLC_CODEC_MPGV;
+        }
+    }
+
+    /* Track timestamps and flag missing PAT */
+    if( !p_sys->patfix.i_timesourcepid && i_dts > -1 )
+    {
+        p_sys->patfix.i_first_dts = i_dts;
+        p_sys->patfix.i_timesourcepid = pid->i_pid;
+    }
+    else if( p_sys->patfix.i_timesourcepid == pid->i_pid && i_dts > -1 &&
+             !p_sys->patfix.b_pat_deadline )
+    {
+        if( i_dts - p_sys->patfix.i_first_dts > 9 * 140000 / 100 )
+            p_sys->patfix.b_pat_deadline = true;
+    }
+
+}
+
+static void BuildPATCallback( void *p_opaque, block_t *p_block )
+{
+    ts_pid_t *pat_pid = (ts_pid_t *) p_opaque;
+    dvbpsi_PushPacket( pat_pid->psi->handle, p_block->p_buffer );
+}
+
+static void BuildPMTCallback( void *p_opaque, block_t *p_block )
+{
+    ts_pid_t *program_pid = (ts_pid_t *) p_opaque;
+    while( p_block )
+    {
+        for( int i_prg = 0; i_prg < program_pid->psi->i_prg; i_prg++ )
+        {
+            dvbpsi_PushPacket( program_pid->psi->prg[i_prg]->handle,
+                               p_block->p_buffer );
+        }
+        p_block = p_block->p_next;
+    }
+}
+
+static void MissingPATPMTFixup( demux_t *p_demux )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    int i_program_number = 1234;
+    int i_program_pid = 1337;
+    int i_pcr_pid = 0x1FFF;
+    int i_num_pes = 0;
+
+    if( p_sys->pid[i_program_pid].b_seen )
+    {
+        /* Find a free one */
+        for( i_program_pid = MIN_ES_PID;
+             i_program_pid < MAX_ES_PID && p_sys->pid[i_program_pid].b_seen;
+             i_program_pid++ );
+    }
+
+    for( int i = MIN_ES_PID; i < MAX_ES_PID; i++ )
+    {
+        if( !p_sys->pid[i].b_seen ||
+            p_sys->pid[i].probed.i_type == -1 )
+            continue;
+
+        if( i_pcr_pid == 0x1FFF && ( p_sys->pid[i].probed.i_type == 0x03 ||
+                                     p_sys->pid[i].probed.b_haspcr ) )
+            i_pcr_pid = p_sys->pid[i].i_pid;
+
+        i_num_pes++;
+    }
+
+    if( i_num_pes == 0 )
+        return;
+
+    ts_stream_t patstream =
+    {
+        .i_pid = 0,
+        .i_continuity_counter = 0x10,
+        .b_discontinuity = false
+    };
+
+    ts_stream_t pmtprogramstream =
+    {
+        .i_pid = i_program_pid,
+        .i_continuity_counter = 0x0,
+        .b_discontinuity = false
+    };
+
+    BuildPAT( DVBPSI_HANDLE_PARAM(p_sys->pid[0].psi->handle)
+            &p_sys->pid[0], BuildPATCallback,
+            0, 1,
+            &patstream,
+            1, &pmtprogramstream, &i_program_number );
+
+    if( !p_sys->pid[i_program_pid].psi )
+    {
+        msg_Err( p_demux, "PAT creation failed" );
+        return;
+    }
+
+    struct esstreams_t
+    {
+        pes_stream_t pes;
+        ts_stream_t ts;
+    };
+    es_format_t esfmt = {0};
+    struct esstreams_t *esstreams = calloc( i_num_pes, sizeof(struct esstreams_t) );
+    pes_mapped_stream_t *mapped = calloc( i_num_pes, sizeof(pes_mapped_stream_t) );
+    if( esstreams && mapped )
+    {
+        int j=0;
+        for( int i = MIN_ES_PID; i < MAX_ES_PID; i++ )
+        {
+            if( !p_sys->pid[i].b_seen ||
+                p_sys->pid[i].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;
+            mapped[j].pes = &esstreams[j].pes;
+            mapped[j].ts = &esstreams[j].ts;
+            mapped[j].fmt = &esfmt;
+            j++;
+        }
+
+        BuildPMT( DVBPSI_HANDLE_PARAM(p_sys->pid[0].psi->handle) VLC_OBJECT(p_demux),
+                &p_sys->pid[i_program_pid], BuildPMTCallback,
+                0, 1,
+                i_pcr_pid,
+                NULL,
+                1, &pmtprogramstream, &i_program_number,
+                i_num_pes, mapped );
+    }
+    free(esstreams);
+    free(mapped);
+}
+
 /*****************************************************************************
  * Open
  *****************************************************************************/
@@ -686,6 +981,8 @@ static int Open( vlc_object_t *p_this )
         pid->i_pid      = i;
         pid->b_seen     = false;
         pid->b_valid    = false;
+        pid->probed.i_fourcc = 0;
+        pid->probed.i_type = 0;
     }
     /* PID 8191 is padding */
     p_sys->pid[8191].b_seen = true;
@@ -785,6 +1082,7 @@ static int Open( vlc_object_t *p_this )
     /* Init PMT array */
     TAB_INIT( p_sys->i_pmt, p_sys->pmt );
     p_sys->i_pmt_es = 0;
+    p_sys->b_delay_es_creation = true;
 
     /* Read config */
     p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" );
@@ -884,11 +1182,17 @@ static int Open( vlc_object_t *p_this )
         }
     }
 
-    while( p_sys->i_pmt_es <= 0 && vlc_object_alive( p_demux ) )
+    while( p_sys->i_pmt_es <= 0
+           && (!p_sys->pid[0].b_seen && !p_sys->patfix.b_pat_deadline) )
     {
         if( Demux( p_demux ) != 1 )
             break;
     }
+
+    /* If we had no PAT within 140ms, create PAT/PMT from probed streams */
+    if( p_sys->i_pmt_es == 0 && !p_sys->pid[0].b_seen )
+        MissingPATPMTFixup( p_demux );
+
     return VLC_SUCCESS;
 }
 
@@ -1037,6 +1341,15 @@ static int Demux( demux_t *p_demux )
         /* Parse the TS packet */
         ts_pid_t *p_pid = &p_sys->pid[PIDGet( p_pkt )];
 
+        /* Probe streams to build PAT/PMT after 140ms in case we don't see any PAT */
+        if( !p_sys->pid[0].b_seen &&
+            (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 */
+        {
+            ProbePES( p_demux, p_pid, p_pkt->p_buffer + 4, p_pkt->p_buffer[3] & 0x20 /* Adaptation field */);
+        }
+
         if( p_pid->b_valid )
         {
             if( p_pid->psi )
@@ -1057,6 +1370,8 @@ static int Demux( demux_t *p_demux )
             }
             else
             {
+                if(p_sys->b_delay_es_creation) /* No longer delay ES since that pid's program sends data */
+                    AddAndCreateES( p_demux, NULL );
                 b_frame = GatherData( p_demux, p_pid, p_pkt );
             }
         }
@@ -1779,9 +2094,13 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes )
             if( header[7]&0x80 )    /* has pts */
             {
                 i_pts = ExtractPESTimestamp( &header[9] );
+                i_pts = AdjustPTSWrapAround( p_demux, i_pts );
 
                 if( header[7]&0x40 )    /* has dts */
+                {
                     i_dts = ExtractPESTimestamp( &header[14] );
+                    i_dts = AdjustPTSWrapAround( p_demux, i_dts );
+                }
             }
         }
         else
@@ -2073,7 +2392,7 @@ static block_t* ReadTSPacket( demux_t *p_demux )
     {
         msg_Warn( p_demux, "lost synchro" );
         block_Release( p_pkt );
-        while( vlc_object_alive (p_demux) )
+        for( ;; )
         {
             const uint8_t *p_peek;
             int i_peek, i_skip = 0;
@@ -2133,6 +2452,32 @@ static mtime_t AdjustPCRWrapAround( demux_t *p_demux, mtime_t i_pcr )
     return i_pcr + i_adjust;
 }
 
+static mtime_t AdjustPTSWrapAround( demux_t *p_demux, mtime_t i_pts )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    mtime_t i_pcr = p_sys->i_current_pcr;
+
+    mtime_t i_adjustremain = i_pcr % 0x1FFFFFFFF;
+    mtime_t i_adjustbase = i_pcr - i_adjustremain;
+
+    mtime_t i_pts_adjust = i_adjustbase;
+
+    /* PTS has rolled first */
+    if( i_adjustremain >= 0xFFFFFFFF && i_pts < 0xFFFFFFFF )
+    {
+        i_pts_adjust += 0x1FFFFFFFF;
+    }
+    /* PCR has rolled first (PTS is late!) */
+    else if( i_adjustremain < 0xFFFFFFFF && i_pts >= 0xFFFFFFFF )
+    {
+        if( i_adjustbase >= 0x1FFFFFFFF ) /* we need to remove current roll */
+            i_pts_adjust -= 0x1FFFFFFFF;
+    }
+
+    i_pts += i_pts_adjust;
+    return i_pts;
+}
+
 static mtime_t GetPCR( block_t *p_pkt )
 {
     const uint8_t *p = p_pkt->p_buffer;
@@ -2170,7 +2515,7 @@ static int SeekToPCR( demux_t *p_demux, int64_t i_pos )
     if( stream_Seek( p_sys->stream, i_pos ) )
         return VLC_EGENERIC;
 
-    while( vlc_object_alive( p_demux ) )
+    for( ;; )
     {
         block_t *p_pkt;
 
@@ -2280,7 +2625,7 @@ static void GetFirstPCR( demux_t *p_demux )
     if( stream_Seek( p_sys->stream, 0 ) )
         return;
 
-    while( vlc_object_alive (p_demux) )
+    for( ;; )
     {
         block_t     *p_pkt;
 
@@ -2321,7 +2666,7 @@ static void GetLastPCR( demux_t *p_demux )
     if( i_pos < 0 && i_pos >= i_stream_size )
         return;
 
-    while( vlc_object_alive( p_demux ) )
+    for( ;; )
     {
         if( SeekToPCR( p_demux, i_pos ) )
             break;
@@ -2329,20 +2674,7 @@ static void GetLastPCR( demux_t *p_demux )
         if( ( i_pos = stream_Tell( p_sys->stream ) ) >= i_last_pos )
             break;
     }
-    if( p_sys->i_last_pcr >= 0 )
-    {
-        int64_t i_size = stream_Size( p_sys->stream );
-        mtime_t i_duration_msec = ( p_sys->i_last_pcr - p_sys->i_first_pcr ) * 100 / 9 / 1000;
-        int64_t i_rate = ( i_size < 0 || i_duration_msec <= 0 ) ? 0 : i_size * 1000 * 8 / i_duration_msec;
-        const int64_t TS_SUPPOSED_MAXRATE = 55 * 1000 * 1000; //FIXME I think it's enough.
-        const int64_t TS_SUPPOSED_MINRATE = 0.5 * 1000 * 1000; //FIXME
-        if( i_rate < TS_SUPPOSED_MINRATE || i_rate > TS_SUPPOSED_MAXRATE )
-        {
-            msg_Dbg( p_demux, "calculated bitrate (%"PRId64"bit/s) is too low or too high. min bitrate (%"PRId64"bit/s) max bitrate (%"PRId64"bit/s)",
-                     i_rate, TS_SUPPOSED_MINRATE, TS_SUPPOSED_MAXRATE );
-            p_sys->i_last_pcr = -1;
-        }
-    }
+
     stream_Seek( p_sys->stream, i_initial_pos );
     assert( i_initial_pos == stream_Tell( p_sys->stream ) );
     p_sys->i_current_pcr = i_initial_pcr;
@@ -2361,7 +2693,7 @@ static void CheckPCR( demux_t *p_demux )
     p_sys->p_pcrs[0] = p_sys->i_first_pcr;
     p_sys->p_pos[0] = i_initial_pos;
 
-    for( i = 1; i < p_sys->i_pcrs_num && vlc_object_alive( p_demux ); ++i )
+    for( i = 1; i < p_sys->i_pcrs_num; ++i )
     {
         /* Round i_pos to a multiple of p_sys->i_packet_size */
         int64_t i_pos = i_size / p_sys->i_pcrs_num * i;
@@ -2398,13 +2730,15 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     if( i_pcr < 0 )
         return;
 
+    i_pcr = AdjustPCRWrapAround( p_demux, i_pcr );
+
     if( p_sys->i_pid_ref_pcr == pid->i_pid )
-        p_sys->i_current_pcr = AdjustPCRWrapAround( p_demux, i_pcr );
+        p_sys->i_current_pcr = i_pcr;
 
     /* Search program and set the PCR */
-    int i_group = -1;
-    for( int i = 0; i < p_sys->i_pmt && i_group < 0 ; i++ )
+    for( int i = 0; i < p_sys->i_pmt; i++ )
     {
+        int i_group = -1;
         for( int i_prg = 0; i_prg < p_sys->pmt[i]->psi->i_prg; i_prg++ )
         {
             ts_prg_psi_t *p_prg = p_sys->pmt[i]->psi->prg[i_prg];
@@ -3082,9 +3416,9 @@ static void SDTCallBack( demux_t *p_demux, dvbpsi_sdt_t *p_sdt )
 
     msg_Dbg( p_demux, "SDTCallBack called" );
 
-    if( sdt->psi->i_sdt_version != -1 &&
-        ( !p_sdt->b_current_next ||
-          p_sdt->i_version == sdt->psi->i_sdt_version ) )
+    if( p_sys->b_delay_es_creation ||
+       !p_sdt->b_current_next ||
+        p_sdt->i_version == sdt->psi->i_sdt_version )
     {
         dvbpsi_DeleteSDT( p_sdt );
         return;
@@ -4355,6 +4689,10 @@ static bool PMTSetupEsHDMV( demux_t *p_demux, ts_pid_t *pid,
         p_fmt->i_cat = AUDIO_ES;
         p_fmt->i_codec = VLC_CODEC_BD_LPCM;
         break;
+    case 0x81:
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_A52;
+        break;
     case 0x82:
     case 0x85: /* DTS-HD High resolution audio */
     case 0x86: /* DTS-HD Master audio */
@@ -4380,6 +4718,10 @@ static bool PMTSetupEsHDMV( demux_t *p_demux, ts_pid_t *pid,
     case 0x91: /* Interactive graphics */
     case 0x92: /* Subtitle */
         return false;
+    case 0xEA:
+        p_fmt->i_cat = VIDEO_ES;
+        p_fmt->i_codec = VLC_CODEC_VC1;
+        break;
     default:
         msg_Info( p_demux, "HDMV registration not implemented for pid 0x%x type 0x%x",
                   p_es->i_pid, p_es->i_type );
@@ -4499,6 +4841,54 @@ static void PMTParseEsIso639( demux_t *p_demux, ts_pid_t *pid,
 #endif
 }
 
+static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid )
+{
+    demux_sys_t  *p_sys = p_demux->p_sys;
+    bool b_create_delayed = false;
+
+    if( pid )
+    {
+        if( pid->b_seen && p_sys->b_delay_es_creation )
+        {
+            p_sys->b_delay_es_creation = false;
+            b_create_delayed = true;
+        }
+
+        if( !p_sys->b_delay_es_creation )
+        {
+            pid->es->id = es_out_Add( p_demux->out, &pid->es->fmt );
+            for( int i = 0; i < pid->i_extra_es; i++ )
+            {
+                pid->extra_es[i]->id =
+                    es_out_Add( p_demux->out, &pid->extra_es[i]->fmt );
+            }
+            p_sys->i_pmt_es += 1 + pid->i_extra_es;
+        }
+    }
+    else if( p_sys->b_delay_es_creation )
+    {
+        p_sys->b_delay_es_creation = false;
+        b_create_delayed = true;
+    }
+
+    if( b_create_delayed )
+    {
+        for(int i=MIN_ES_PID; i<MAX_ES_PID; i++)
+        {
+            pid = &p_sys->pid[i];
+            if(!pid->es || pid->es->id)
+                continue;
+            pid->es->id = es_out_Add( p_demux->out, &pid->es->fmt );
+            for( int j = 0; j < pid->i_extra_es; j++ )
+            {
+                pid->extra_es[j]->id =
+                    es_out_Add( p_demux->out, &pid->extra_es[j]->fmt );
+            }
+            p_sys->i_pmt_es += 1 + pid->i_extra_es;
+        }
+    }
+}
+
 static void PMTCallBack( void *data, dvbpsi_pmt_t *p_pmt )
 {
     demux_t      *p_demux = data;
@@ -4645,7 +5035,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_pmt )
     dvbpsi_pmt_es_t      *p_es;
     for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
     {
-        ts_pid_t tmp_pid, *old_pid = 0, *pid = &tmp_pid;
+        ts_pid_t tmp_pid = {0}, *old_pid = {0}, *pid = &tmp_pid;
 
         /* Find out if the PID was already declared */
         for( int i = 0; i < i_clean; i++ )
@@ -4846,13 +5236,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_pmt )
             }
             else
             {
-                pid->es->id = es_out_Add( p_demux->out, &pid->es->fmt );
-                for( int i = 0; i < pid->i_extra_es; i++ )
-                {
-                    pid->extra_es[i]->id =
-                        es_out_Add( p_demux->out, &pid->extra_es[i]->fmt );
-                }
-                p_sys->i_pmt_es += 1 + pid->i_extra_es;
+                AddAndCreateES( p_demux, pid );
             }
         }