]> git.sesse.net Git - vlc/blobdiff - modules/demux/ts.c
* packetizer/h264.c: a really basic h264 packetizer (it doesn't support
[vlc] / modules / demux / ts.c
index a1b0a08469a2c480941ebce4d513607802190d60..2b2d39472df6efa81960cd66a26a57474bea2667 100644 (file)
@@ -2,7 +2,7 @@
  * ts.c: Transport Stream input module for VLC.
  *****************************************************************************
  * Copyright (C) 2004 VideoLAN
- * $Id: ts.c,v 1.1 2004/01/16 01:47:41 fenrir Exp $
+ * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -30,6 +30,9 @@
 #include <vlc/input.h>
 
 #include "iso_lang.h"
+#include "network.h"
+
+#include "../mux/mpeg/csa.h"
 
 /* Include dvbpsi headers */
 #ifdef HAVE_DVBPSI_DR_H
@@ -49,6 +52,7 @@
 #endif
 
 /* TODO:
+ *  - XXX: do not mark options message to be translated, they are too osbcure for now ...
  *  - test it
  *  - ...
  */
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-static int  Open    ( vlc_object_t * );
-static void Close  ( vlc_object_t * );
+static int  Open  ( vlc_object_t * );
+static void Close ( vlc_object_t * );
 
 vlc_module_begin();
     set_description( _("ISO 13818-1 MPEG Transport Stream input - new" ) );
-    add_category_hint( "TS demuxer", NULL, VLC_TRUE );
-        add_string( "ts-extra-pmt", NULL, NULL, "extra PMT", "allow user to specify an extra pmt (pmt_pid=pid:stream_type[,...])", VLC_TRUE );
+    add_string( "ts-extra-pmt", NULL, NULL, "extra PMT", "allow user to specify an extra pmt (pmt_pid=pid:stream_type[,...])", VLC_TRUE );
+    add_bool( "ts-es-id-pid", 0, NULL, "set id of es to pid", "set id of es to pid", VLC_TRUE );
+    add_string( "ts-out", NULL, NULL, "fast udp streaming", "send TS to specific ip:port by udp (you must know what you are doing)", VLC_TRUE );
+    add_integer( "ts-out-mtu", 1500, NULL, "MTU for out mode", "MTU for out mode", VLC_TRUE );
+    add_string( "ts-csa-ck", NULL, NULL, "CSA ck", "CSA ck", VLC_TRUE );
     set_capability( "demux2", 10 );
     set_callbacks( Open, Close );
     add_shortcut( "ts2" );
@@ -191,18 +198,33 @@ typedef struct
 
 struct demux_sys_t
 {
+    /* how many TS packet we read at once */
+    int         i_ts_read;
+
     /* All pid */
     ts_pid_t    pid[8192];
 
     /* All PMT */
     int         i_pmt;
     ts_pid_t    **pmt;
+
+    /* */
+    vlc_bool_t  b_es_id_pid;
+    csa_t       *csa;
+
+    vlc_bool_t  b_udp_out;
+    int         fd; /* udp socket */
+    uint8_t     *buffer;
 };
 
 static int Demux  ( demux_t *p_demux );
 static int Control( demux_t *p_demux, int i_query, va_list args );
 
-static void PIDInit( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner );
+
+static void PIDInit ( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner );
+static void PIDClean( es_out_t *out, ts_pid_t *pid );
+static int  PIDFillFormat( ts_pid_t *pid, int i_stream_type );
+
 static void PATCallBack( demux_t *, dvbpsi_pat_t * );
 static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt );
 
@@ -212,12 +234,12 @@ static inline int PIDGet( block_t *p )
 }
 
 static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
-static char *LanguageNameISO639( char *p );
+
+static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
 
 static iod_descriptor_t *IODNew( int , uint8_t * );
-static void IODFree( iod_descriptor_t * );
+static void              IODFree( iod_descriptor_t * );
 
-static int ESFillFormat( es_format_t *fmt, int i_stream_type );
 
 /*****************************************************************************
  * Open
@@ -229,6 +251,7 @@ static int Open( vlc_object_t *p_this )
 
     uint8_t     *p_peek;
     int          i_peek;
+    int          i_sync;
     int          i;
 
     ts_pid_t     *pat;
@@ -240,15 +263,37 @@ static int Open( vlc_object_t *p_this )
         msg_Err( p_demux, "cannot peek" );
         return VLC_EGENERIC;
     }
-    if( p_peek[0] != 0x47 || ( i_peek >= 189 && p_peek[188] != 0x47 ) )
+
+    /* Search first synch */
+    for( i_sync = 0; i_sync < i_peek; i_sync++ )
+    {
+        if( p_peek[i_sync] == 0x47 ) break;
+    }
+    if( i_sync >= i_peek )
     {
-        if( strcmp( p_demux->psz_demux, "ts" ) )
+        if( strcmp( p_demux->psz_demux, "ts2" ) )
         {
             msg_Warn( p_demux, "TS module discarded" );
             return VLC_EGENERIC;
         }
         msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
     }
+    if( strcmp( p_demux->psz_demux, "ts2" ) )
+    {
+        /* Check next 3 sync points */
+        i_peek = 188*3 + 1 + i_sync;
+        if( ( stream_Peek( p_demux->s, &p_peek, i_peek ) ) < i_peek )
+        {
+            msg_Err( p_demux, "cannot peek" );
+            return VLC_EGENERIC;
+        }
+        if( p_peek[i_sync+  188] != 0x47 || p_peek[i_sync+2*188] != 0x47 ||
+            p_peek[i_sync+3*188] != 0x47 )
+        {
+            msg_Warn( p_demux, "TS module discarded (lost sync)" );
+            return VLC_EGENERIC;
+        }
+    }
 
     /* Fill p_demux field */
     p_demux->pf_demux = Demux;
@@ -265,6 +310,9 @@ static int Open( vlc_object_t *p_this )
         pid->b_seen     = VLC_FALSE;
         pid->b_valid    = VLC_FALSE;
     }
+    p_sys->b_udp_out = VLC_FALSE;
+    p_sys->i_ts_read = 50;
+    p_sys->csa = NULL;
 
     /* Init PAT handler */
     pat = &p_sys->pid[0];
@@ -275,6 +323,53 @@ static int Open( vlc_object_t *p_this )
     p_sys->i_pmt = 0;
     p_sys->pmt   = NULL;
 
+    /* Read config */
+    var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Get( p_demux, "ts-es-id-pid", &val );
+    p_sys->b_es_id_pid = val.b_bool,
+
+    var_Create( p_demux, "ts-out", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+    var_Get( p_demux, "ts-out", &val );
+    if( val.psz_string && *val.psz_string )
+    {
+        vlc_value_t mtu;
+        char *psz = strchr( val.psz_string, ':' );
+        int   i_port = 0;
+
+        p_sys->b_udp_out = VLC_TRUE;
+
+        if( psz )
+        {
+            *psz++ = '\0';
+            i_port = atoi( psz );
+        }
+        if( i_port <= 0 ) i_port  = 1234;
+        msg_Dbg( p_demux, "resend ts to '%s:%d'", val.psz_string, i_port );
+
+        p_sys->fd = net_OpenUDP( p_demux, "", 0, val.psz_string, i_port );
+        if( p_sys->fd < 0 )
+        {
+            msg_Err( p_demux, "failed to open udp socket, send disabled" );
+            p_sys->b_udp_out = VLC_FALSE;
+        }
+        else
+        {
+            var_Create( p_demux, "ts-out-mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+            var_Get( p_demux, "ts-out-mtu", &mtu );
+            p_sys->i_ts_read = mtu.i_int / 188;
+            if( p_sys->i_ts_read <= 0 )
+            {
+                p_sys->i_ts_read = 1500 / 188;
+            }
+            p_sys->buffer = malloc( 188 * p_sys->i_ts_read );
+        }
+    }
+    if( val.psz_string )
+    {
+        free( val.psz_string );
+    }
+
+
     /* We handle description of an extra PMT */
     var_Create( p_demux, "ts-extra-pmt", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
     var_Get( p_demux, "ts-extra-pmt", &val );
@@ -287,7 +382,7 @@ static int Open( vlc_object_t *p_this )
         {
             ts_pid_t *pmt = &p_sys->pid[i_pid];
 
-            msg_Dbg( p_demux, "Extra pmt specified (pid=0x%x)", i_pid );
+            msg_Dbg( p_demux, "extra pmt specified (pid=0x%x)", i_pid );
             PIDInit( pmt, VLC_TRUE, NULL );
             /* FIXME we should also ask for a number */
             pmt->psi->handle = dvbpsi_AttachPMT( 1, (dvbpsi_pmt_callback)PMTCallBack, p_demux );
@@ -317,9 +412,13 @@ static int Open( vlc_object_t *p_this )
                         {
                             pmt->psi->i_pid_pcr = i_pid;
                         }
-                        ESFillFormat( &pid->es->fmt, i_stream_type);
+                        PIDFillFormat( pid, i_stream_type);
                         if( pid->es->fmt.i_cat != UNKNOWN_ES )
                         {
+                            if( p_sys->b_es_id_pid )
+                            {
+                                pid->es->fmt.i_id = i_pid;
+                            }
                             msg_Dbg( p_demux, "  * es pid=0x%x type=0x%x fcc=%4.4s", i_pid, i_stream_type, (char*)&pid->es->fmt.i_codec );
                             pid->es->id = es_out_Add( p_demux->out, &pid->es->fmt );
                         }
@@ -334,6 +433,42 @@ static int Open( vlc_object_t *p_this )
         free( val.psz_string );
     }
 
+    var_Create( p_demux, "ts-csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+    var_Get( p_demux, "ts-csa-ck", &val );
+    if( val.psz_string && *val.psz_string )
+    {
+        char *psz = val.psz_string;
+        if( psz[0] == '0' && ( psz[1] == 'x' || psz[1] == 'X' ) )
+        {
+            psz += 2;
+        }
+        if( strlen( psz ) != 16 )
+        {
+            msg_Warn( p_demux, "invalid csa ck (it must be 16 chars long)" );
+        }
+        else
+        {
+            uint64_t i_ck = strtoll( psz, NULL, 16 );
+            uint8_t ck[8];
+            int     i;
+            for( i = 0; i < 8; i++ )
+            {
+                ck[i] = ( i_ck >> ( 56 - 8*i) )&0xff;
+            }
+
+            msg_Dbg( p_demux, "using CSA scrambling with ck=%x:%x:%x:%x:%x:%x:%x:%x",
+                     ck[0], ck[1], ck[2], ck[3], ck[4], ck[5], ck[6], ck[7] );
+
+            p_sys->csa = csa_New();
+            csa_SetCW( p_sys->csa, ck, ck );
+        }
+    }
+    if( val.psz_string )
+    {
+        free( val.psz_string );
+    }
+
+
     return VLC_SUCCESS;
 }
 
@@ -385,10 +520,20 @@ static void Close( vlc_object_t *p_this )
         }
     }
 
+    if( p_sys->b_udp_out )
+    {
+        net_Close( p_sys->fd );
+        free( p_sys->buffer );
+    }
+    if( p_sys->csa )
+    {
+        csa_Delete( p_sys->csa );
+    }
+
+    if( p_sys->i_pmt ) free( p_sys->pmt );
     free( p_sys );
 }
 
-
 /*****************************************************************************
  * Demux:
  *****************************************************************************/
@@ -398,7 +543,7 @@ static int Demux( demux_t *p_demux )
     int          i_pkt;
 
     /* We read at most 100 TS packet or until a frame is completed */
-    for( i_pkt = 0; i_pkt < 100; i_pkt++ )
+    for( i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
     {
         vlc_bool_t  b_frame = VLC_FALSE;
         block_t     *p_pkt;
@@ -416,7 +561,7 @@ static int Demux( demux_t *p_demux )
             block_Release( p_pkt );
 
             /* Resynch */
-            for( ;; )
+            while( !p_demux->b_die )
             {
                 uint8_t    *p_peek;
                 int         i_peek = stream_Peek( p_demux->s, &p_peek, 1880 );
@@ -452,6 +597,11 @@ static int Demux( demux_t *p_demux )
             }
         }
 
+        if( p_sys->b_udp_out )
+        {
+            memcpy( &p_sys->buffer[i_pkt*188], p_pkt->p_buffer, 188 );
+        }
+
         /* Parse the TS packet */
         p_pid = &p_sys->pid[PIDGet( p_pkt )];
 
@@ -462,10 +612,14 @@ static int Demux( demux_t *p_demux )
                 dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
                 block_Release( p_pkt );
             }
-            else
+            else if( !p_sys->b_udp_out )
             {
                 b_frame = GatherPES( p_demux, p_pid, p_pkt );
             }
+            else
+            {
+                block_Release( p_pkt );
+            }
         }
         else
         {
@@ -473,6 +627,8 @@ static int Demux( demux_t *p_demux )
             {
                 msg_Dbg( p_demux, "pid[0x%x] unknown", p_pid->i_pid );
             }
+            /* We have to handle PCR if present */
+            PCRHandle( p_demux, p_pid, p_pkt );
             block_Release( p_pkt );
         }
         p_pid->b_seen = VLC_TRUE;
@@ -483,6 +639,12 @@ static int Demux( demux_t *p_demux )
         }
     }
 
+    if( p_sys->b_udp_out )
+    {
+        /* Send the complete block */
+        net_Write( p_demux, p_sys->fd, p_sys->buffer, p_sys->i_ts_read * 188 );
+    }
+
     return 1;
 }
 
@@ -491,9 +653,9 @@ static int Demux( demux_t *p_demux )
  *****************************************************************************/
 static int Control( demux_t *p_demux, int i_query, va_list args )
 {
-    demux_sys_t *p_sys = p_demux->p_sys;
+    /* demux_sys_t *p_sys = p_demux->p_sys; */
     double f, *pf;
-    int64_t i64, *pi64;
+    int64_t i64;
 
     switch( i_query )
     {
@@ -531,7 +693,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             *pi64 = p_sys->i_time;
             return VLC_SUCCESS;
 
-#if 0
         case DEMUX_GET_LENGTH:
             pi64 = (int64_t*)va_arg( args, int64_t * );
             if( p_sys->i_mux_rate > 0 )
@@ -541,14 +702,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             }
             *pi64 = 0;
             return VLC_EGENERIC;
-
-        case DEMUX_SET_TIME:
 #endif
         case DEMUX_GET_FPS:
-            pf = (double*)va_arg( args, double * );
-            *pf = (double)1000000.0 / (double)p_sys->i_pcr_inc;
-            return VLC_SUCCESS;
-#endif
+        case DEMUX_SET_TIME:
         default:
             return VLC_EGENERIC;
     }
@@ -583,6 +739,35 @@ static void PIDInit( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner )
     }
 }
 
+static void PIDClean( es_out_t *out, ts_pid_t *pid )
+{
+    if( pid->psi )
+    {
+        if( pid->psi->handle )
+        {
+            dvbpsi_DetachPMT( pid->psi->handle );
+        }
+        if( pid->psi->iod )
+        {
+            IODFree( pid->psi->iod );
+        }
+        free( pid->psi );
+    }
+    else
+    {
+        if( pid->es->id )
+        {
+            es_out_Del( out, pid->es->id );
+        }
+        if( pid->es->p_pes )
+        {
+            block_ChainRelease( pid->es->p_pes );
+        }
+        free( pid->es );
+    }
+    pid->b_valid = VLC_FALSE;
+}
+
 /****************************************************************************
  * gathering stuff
  ****************************************************************************/
@@ -604,7 +789,7 @@ static void ParsePES ( demux_t *p_demux, ts_pid_t *pid )
 
     if( header[0] != 0 || header[1] != 0 || header[2] != 1 )
     {
-        msg_Err( p_demux, "invalid header [0x%x:%x:%x:%x]", header[0], header[1],header[2],header[3] );
+        msg_Warn( p_demux, "invalid header [0x%x:%x:%x:%x]", header[0], header[1],header[2],header[3] );
         block_ChainRelease( p_pes );
         return;
     }
@@ -737,22 +922,53 @@ static void ParsePES ( demux_t *p_demux, ts_pid_t *pid )
         {
             p_pes->i_pts = i_pts * 100 / 9;
         }
-        es_out_Send( p_demux->out, pid->es->id, p_pes );
+
+        /* For mpeg4/mscodec we first gather the packet -> will make ffmpeg happier */
+        es_out_Send( p_demux->out, pid->es->id, block_ChainGather( p_pes ) );
     }
     else
     {
         msg_Warn( p_demux, "empty pes" );
     }
-};
+}
 
-static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
+static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
 {
-    uint8_t     *p = p_bk->p_buffer;
+    demux_sys_t   *p_sys = p_demux->p_sys;
+    const uint8_t *p = p_bk->p_buffer;
+
+    if( ( p[3]&0x20 ) && /* adaptation */
+        ( p[5]&0x10 ) &&
+        ( p[4] >= 7 ) )
+    {
+        int i;
+        mtime_t i_pcr;  /* 33 bits */
+
+        i_pcr = ( (mtime_t)p[6] << 25 ) |
+                ( (mtime_t)p[7] << 17 ) |
+                ( (mtime_t)p[8] << 9 ) |
+                ( (mtime_t)p[9] << 1 ) |
+                ( (mtime_t)p[10] >> 7 );
 
-    vlc_bool_t  b_unit_start= p[1]&0x40;
-    vlc_bool_t  b_adaptation= p[3]&0x20;
-    vlc_bool_t  b_payload   = p[3]&0x10;
-    int         i_cc = p[3]&0x0f;   /* continuity counter */
+        /* Search program and set the PCR */
+        for( i = 0; i < p_sys->i_pmt; i++ )
+        {
+            if( pid->i_pid == p_sys->pmt[i]->psi->i_pid_pcr )
+            {
+                es_out_Control( p_demux->out, ES_OUT_SET_GROUP_PCR,
+                                (int)p_sys->pmt[i]->psi->i_number,
+                                (int64_t)(i_pcr * 100 / 9) );
+            }
+        }
+    }
+}
+
+static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
+{
+    const uint8_t    *p = p_bk->p_buffer;
+    const vlc_bool_t  b_adaptation= p[3]&0x20;
+    const vlc_bool_t  b_payload   = p[3]&0x10;
+    const int         i_cc        = p[3]&0x0f;   /* continuity counter */
     /* transport_scrambling_control is ignored */
 
     int         i_skip = 0;
@@ -766,6 +982,11 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
         msg_Dbg( p_demux, "transport_error_indicator set (pid=0x%x)", pid->i_pid );
     }
 
+    if( p_demux->p_sys->csa )
+    {
+        csa_Decrypt( p_demux->p_sys->csa, p_bk->p_buffer );
+    }
+
     if( !b_adaptation )
     {
         i_skip = 4;
@@ -798,7 +1019,7 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     {
         if( pid->i_cc == 0xff )
         {
-            msg_Warn( p_demux, "first packet for pid=0x%x c=0x%x", pid->i_pid, i_cc );
+            msg_Warn( p_demux, "first packet for pid=0x%x cc=0x%x", pid->i_pid, i_cc );
             pid->i_cc = i_cc;
         }
         else if( i_diff != 0 )
@@ -811,33 +1032,21 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
 
             if( pid->es->p_pes )
             {
-                block_ChainRelease( pid->es->p_pes );
-                pid->es->p_pes = NULL;
+                pid->es->p_pes->i_flags |= BLOCK_FLAG_DISCONTINUITY;
             }
         }
     }
 
-    if( b_adaptation &&
-        (p[5] & 0x10) && p[4]>=7 && pid->p_owner && pid->p_owner->i_pid_pcr == pid->i_pid )
-    {
-        mtime_t i_pcr;  /* 33 bits */
+    PCRHandle( p_demux, pid, p_bk );
 
-        i_pcr = ( (mtime_t)p[6] << 25 ) |
-                ( (mtime_t)p[7] << 17 ) |
-                ( (mtime_t)p[8] << 9 ) |
-                ( (mtime_t)p[9] << 1 ) |
-                ( (mtime_t)p[10] >> 7 );
-
-        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_PCR, (int)pid->p_owner->i_number, (int64_t)(i_pcr * 100 / 9) );
-    }
-
-
-    if( i_skip >= 188 || pid->es->id == NULL )
+    if( i_skip >= 188 || pid->es->id == NULL || p_demux->p_sys->b_udp_out )
     {
         block_Release( p_bk );
     }
     else
     {
+        const vlc_bool_t b_unit_start= p[1]&0x40;
+
         /* we have to gather it */
         p_bk->p_buffer += i_skip;
         p_bk->i_buffer -= i_skip;
@@ -870,32 +1079,10 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     return i_ret;
 }
 
-static char *LanguageNameISO639( char *psz_code )
+static int PIDFillFormat( ts_pid_t *pid, int i_stream_type )
 {
-    const iso639_lang_t *pl;
+    es_format_t *fmt = &pid->es->fmt;
 
-    pl = GetLang_2B( psz_code );
-    if( !strcmp( pl->psz_iso639_1, "??" ) )
-    {
-        pl = GetLang_2T( psz_code );
-    }
-
-    if( !strcmp( pl->psz_iso639_1, "??" ) )
-    {
-       return strdup( psz_code );
-    }
-    else
-    {
-        if( *pl->psz_native_name )
-        {
-            return strdup( pl->psz_native_name );
-        }
-        return strdup( pl->psz_eng_name );
-    }
-}
-
-static int ESFillFormat( es_format_t *fmt, int i_stream_type )
-{
     switch( i_stream_type )
     {
         case 0x01:  /* MPEG-1 video */
@@ -954,11 +1141,14 @@ static int ESFillFormat( es_format_t *fmt, int i_stream_type )
             break;
     }
 
+    /* PES packets usually contain truncated frames */
+    fmt->b_packetized = VLC_FALSE;
+
     return fmt->i_cat == UNKNOWN_ES ? VLC_EGENERIC : VLC_SUCCESS ;
 }
 
 /*****************************************************************************
- * MP4 specific functions
+ * MP4 specific functions (IOD parser)
  *****************************************************************************/
 static int  IODDescriptorLength( int *pi_data, uint8_t **pp_data )
 {
@@ -979,38 +1169,32 @@ static int IODGetByte( int *pi_data, uint8_t **pp_data )
 {
     if( *pi_data > 0 )
     {
-        int i_b = **pp_data;
+        const int i_b = **pp_data;
         (*pp_data)++;
         (*pi_data)--;
         return( i_b );
     }
-    else
-    {
-        return( 0 );
-    }
+    return( 0 );
 }
-
-static int MP4_GetWord( int *pi_data, uint8_t **pp_data )
+static int IODGetWord( int *pi_data, uint8_t **pp_data )
 {
-    int i1, i2;
-    i1 = IODGetByte( pi_data, pp_data );
-    i2 = IODGetByte( pi_data, pp_data );
+    const int i1 = IODGetByte( pi_data, pp_data );
+    const int i2 = IODGetByte( pi_data, pp_data );
     return( ( i1 << 8 ) | i2 );
 }
 static int IODGet3Bytes( int *pi_data, uint8_t **pp_data )
 {
-    int i1, i2, i3;
-    i1 = IODGetByte( pi_data, pp_data );
-    i2 = IODGetByte( pi_data, pp_data );
-    i3 = IODGetByte( pi_data, pp_data );
+    const int i1 = IODGetByte( pi_data, pp_data );
+    const int i2 = IODGetByte( pi_data, pp_data );
+    const int i3 = IODGetByte( pi_data, pp_data );
+
     return( ( i1 << 16 ) | ( i2 << 8) | i3 );
 }
 
-static uint32_t IODGetWord( int *pi_data, uint8_t **pp_data )
+static uint32_t IODGetDWord( int *pi_data, uint8_t **pp_data )
 {
-    uint32_t i1, i2;
-    i1 = MP4_GetWord( pi_data, pp_data );
-    i2 = MP4_GetWord( pi_data, pp_data );
+    const uint32_t i1 = IODGetWord( pi_data, pp_data );
+    const uint32_t i2 = IODGetWord( pi_data, pp_data );
     return( ( i1 << 16 ) | i2 );
 }
 
@@ -1128,7 +1312,7 @@ static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data )
                     fprintf( stderr, "\n* - ES_Descriptor length:%d", i_length );
                     es_descr.b_ok = 1;
 
-                    es_descr.i_es_id = MP4_GetWord( &i_data, &p_data );
+                    es_descr.i_es_id = IODGetWord( &i_data, &p_data );
                     i_flags = IODGetByte( &i_data, &p_data );
                     es_descr.b_streamDependenceFlag = ( i_flags >> 7 )&0x01;
                     b_url = ( i_flags >> 6 )&0x01;
@@ -1140,7 +1324,7 @@ static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data )
 
                     if( es_descr.b_streamDependenceFlag )
                     {
-                        es_descr.i_dependOn_es_id = MP4_GetWord( &i_data, &p_data );
+                        es_descr.i_dependOn_es_id = IODGetWord( &i_data, &p_data );
                         fprintf( stderr, "\n*   * dependOn_es_id:%d", es_descr.i_dependOn_es_id );
                     }
 
@@ -1156,7 +1340,7 @@ static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data )
 
                     if( es_descr.b_OCRStreamFlag )
                     {
-                        es_descr.i_OCR_es_id = MP4_GetWord( &i_data, &p_data );
+                        es_descr.i_OCR_es_id = IODGetWord( &i_data, &p_data );
                         fprintf( stderr, "\n*   * OCR_es_id:%d", es_descr.i_OCR_es_id );
                     }
 
@@ -1175,8 +1359,8 @@ static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data )
                     dec_descr.i_streamType = i_flags >> 2;
                     dec_descr.b_upStream = ( i_flags >> 1 )&0x01;
                     dec_descr.i_bufferSizeDB = IODGet3Bytes( &i_data, &p_data );
-                    dec_descr.i_maxBitrate = IODGetWord( &i_data, &p_data );
-                    dec_descr.i_avgBitrate = IODGetWord( &i_data, &p_data );
+                    dec_descr.i_maxBitrate = IODGetDWord( &i_data, &p_data );
+                    dec_descr.i_avgBitrate = IODGetDWord( &i_data, &p_data );
                     fprintf( stderr, "\n*     * objectTypeIndication:0x%x", dec_descr.i_objectTypeIndication  );
                     fprintf( stderr, "\n*     * streamType:0x%x", dec_descr.i_streamType );
                     fprintf( stderr, "\n*     * upStream:%d", dec_descr.b_upStream );
@@ -1360,15 +1544,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
 
         if( pid->b_valid && pid->p_owner == pmt->psi && pid->psi == NULL )
         {
-            pid->b_valid = VLC_FALSE;
-            if( pid->es->id )
-            {
-                es_out_Del( p_demux->out, pid->es->id );
-            }
-            if( pid->es->p_pes )
-            {
-                block_ChainRelease( pid->es->p_pes );
-            }
+            PIDClean( p_demux->out, pid );
         }
     }
     if( pmt->psi->iod )
@@ -1377,7 +1553,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         pmt->psi->iod = NULL;
     }
 
-    msg_Dbg( p_demux, "New PMT program number=%d version=%d pid_pcr=0x%x", p_pmt->i_program_number, p_pmt->i_version, p_pmt->i_pcr_pid );
+    msg_Dbg( p_demux, "new PMT program number=%d version=%d pid_pcr=0x%x", p_pmt->i_program_number, p_pmt->i_version, p_pmt->i_pcr_pid );
     pmt->psi->i_pid_pcr = p_pmt->i_pcr_pid;
     pmt->psi->i_version = p_pmt->i_version;
 
@@ -1387,10 +1563,14 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         if( p_dr->i_tag == 0x1d )
         {
             /* We have found an IOD descriptor */
-            msg_Warn( p_demux, "found IOD descriptor" );
+            msg_Warn( p_demux, " * descriptor : IOD (0x1d)" );
 
             pmt->psi->iod = IODNew( p_dr->i_length, p_dr->p_data );
         }
+        else
+        {
+            msg_Dbg( p_demux, " * descriptor : unknown (0x%x)", p_dr->i_tag );
+        }
     }
 
     for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
@@ -1404,7 +1584,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         }
 
         PIDInit( pid, VLC_FALSE, pmt->psi );
-        ESFillFormat( &pid->es->fmt, p_es->i_type );
+        PIDFillFormat( pid, p_es->i_type );
 
         if( p_es->i_type == 0x10 || p_es->i_type == 0x11 )
         {
@@ -1464,6 +1644,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
 
                         default:
                             pid->es->fmt.i_cat = UNKNOWN_ES;
+                            break;
                     }
                 }
                 else if( dcd->i_streamType == 0x05 )    /* AudioStream */
@@ -1487,6 +1668,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
                             break;
                         default:
                             pid->es->fmt.i_cat = UNKNOWN_ES;
+                            break;
                     }
                 }
                 else
@@ -1513,6 +1695,9 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
 
             for( p_dr = p_es->p_first_descriptor; p_dr != NULL; p_dr = p_dr->p_next )
             {
+                msg_Dbg( p_demux, "  * es pid=0x%x type=0x%x dr->i_tag=0x%x",
+                         p_es->i_pid, p_es->i_type, p_dr->i_tag );
+
                 if( p_dr->i_tag == 0x6a )
                 {
                     pid->es->fmt.i_cat = AUDIO_ES;
@@ -1536,8 +1721,11 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
 
             if( p_dr && p_dr->i_length >= 8 )
             {
+                pid->es->fmt.i_cat = VIDEO_ES;
                 pid->es->fmt.i_codec = VLC_FOURCC( p_dr->p_data[0], p_dr->p_data[1],
                                                    p_dr->p_data[2], p_dr->p_data[3] );
+                pid->es->fmt.video.i_width = ( p_dr->p_data[4] << 8 )|p_dr->p_data[5];
+                pid->es->fmt.video.i_height= ( p_dr->p_data[6] << 8 )|p_dr->p_data[7];
                 pid->es->fmt.i_extra = (p_dr->p_data[8] << 8) | p_dr->p_data[9];
 
                 if( pid->es->fmt.i_extra > 0 )
@@ -1550,6 +1738,9 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
             {
                 msg_Warn( p_demux, "private MSCODEC (vlc) without bih private descriptor" );
             }
+            /* For such stream we will gather them ourself and don't launch a packetize,
+             * Yes it's ugly but it's the only way to make DIV3 working */
+            pid->es->fmt.b_packetized = VLC_TRUE;
         }
 
         if( pid->es->fmt.i_cat == AUDIO_ES || pid->es->fmt.i_cat == SPU_ES )
@@ -1561,8 +1752,13 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
             if( p_dr )
             {
                 dvbpsi_iso639_dr_t *p_decoded = dvbpsi_DecodeISO639Dr( p_dr );
-                pid->es->fmt.psz_language =
-                    LanguageNameISO639( (char*)&p_decoded->i_iso_639_code );
+
+                if( p_decoded )
+                {
+                    pid->es->fmt.psz_language = malloc( 4 );
+                    memcpy( pid->es->fmt.psz_language, p_decoded->i_iso_639_code, 3 );
+                    pid->es->fmt.psz_language[3] = 0;
+                }
             }
         }
 
@@ -1571,9 +1767,13 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         {
             msg_Dbg( p_demux, "  * es pid=0x%x type=0x%x *unknown*", p_es->i_pid, p_es->i_type );
         }
-        else
+        else if( !p_sys->b_udp_out )
         {
             msg_Dbg( p_demux, "  * es pid=0x%x type=0x%x fcc=%4.4s", p_es->i_pid, p_es->i_type, (char*)&pid->es->fmt.i_codec );
+            if( p_sys->b_es_id_pid )
+            {
+                pid->es->fmt.i_id = p_es->i_pid;
+            }
             pid->es->id = es_out_Add( p_demux->out, &pid->es->fmt );
         }
     }
@@ -1589,62 +1789,95 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
 
     msg_Dbg( p_demux, "PATCallBack called" );
 
-    if( pat->psi->i_version != -1 && ( !p_pat->b_current_next || p_pat->i_version == pat->psi->i_version ) )
+    if( pat->psi->i_version != -1 &&
+        ( !p_pat->b_current_next || p_pat->i_version == pat->psi->i_version ) )
     {
         dvbpsi_DeletePAT( p_pat );
         return;
     }
 
-    msg_Dbg( p_demux, "New PAT ts_id=0x%x version=%d current_next=%d", p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
+    msg_Dbg( p_demux, "new PAT ts_id=0x%x version=%d current_next=%d",
+             p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
 
     /* Clean old */
-    for( i = 2; i < 8192; i++ )
+    if( p_sys->i_pmt > 0 )
     {
-        ts_pid_t *pid = &p_sys->pid[i];
+        int      i_pmt_rm = 0;
+        ts_pid_t **pmt_rm = NULL;
 
-        if( pid->b_valid )
+        /* Search pmt to be deleted */
+        for( i = 0; i < p_sys->i_pmt; i++ )
         {
-            if( pid->psi )
+            ts_pid_t *pmt = p_sys->pmt[i];
+            vlc_bool_t b_keep = VLC_FALSE;
+
+            for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
             {
-                if( pid->p_owner == pat->psi )
+                if( p_program->i_pid == pmt->i_pid && p_program->i_number == pmt->psi->i_number )
                 {
-                    dvbpsi_DetachPMT( pid->psi->handle );
-                    if( pid->psi->iod )
-                    {
-                        IODFree( pid->psi->iod );
-                        pid->psi->iod = NULL;
-                    }
-                    pid->b_valid = VLC_FALSE;
-                    TAB_REMOVE( p_sys->i_pmt, p_sys->pmt, pid );
+                    b_keep = VLC_TRUE;
+                    break;
                 }
             }
-            else if( pid->p_owner && pid->p_owner->i_number != 0 && pid->es->id )
+            if( !b_keep )
             {
-                /* We only remove es that aren't defined by extra pmt */
-                es_out_Del( p_demux->out, pid->es->id );
+                TAB_APPEND( i_pmt_rm, pmt_rm, pmt );
+            }
+        }
 
-                pid->b_valid = VLC_FALSE;
+        /* Delete all ES attached to thoses PMT */
+        for( i = 2; i < 8192; i++ )
+        {
+            ts_pid_t *pid = &p_sys->pid[i];
+            if( pid->b_valid && !pid->psi )
+            {
+                for( i = 0; i < i_pmt_rm; i++ )
+                {
+                    if( pid->p_owner->i_pid_pcr == pmt_rm[i]->i_pid && pid->es->id )
+                    {
+                        /* We only remove es that aren't defined by extra pmt */
+                        PIDClean( p_demux->out, pid );
+                        break;
+                    }
+                }
             }
         }
+
+        /* Delete PMT pid */
+        for( i = 0; i < i_pmt_rm; i++ )
+        {
+            PIDClean( p_demux->out, &p_sys->pid[pmt_rm[i]->i_pid] );
+            TAB_REMOVE( p_sys->i_pmt, p_sys->pmt, pmt_rm[i] );
+        }
+        if( pmt_rm )
+        {
+            free( pmt_rm );
+        }
     }
 
     /* now create programs */
-    for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
+    for( p_program = p_pat->p_first_program; p_program != NULL;
+         p_program = p_program->p_next )
     {
-        msg_Dbg( p_demux, "  * number=%d pid=0x%x", p_program->i_number, p_program->i_pid );
+        msg_Dbg( p_demux, "  * number=%d pid=0x%x", p_program->i_number,
+                 p_program->i_pid );
         if( p_program->i_number != 0 )
         {
             ts_pid_t *pmt = &p_sys->pid[p_program->i_pid];
 
-            PIDInit( pmt, VLC_TRUE, pat->psi );
-            pmt->psi->handle = dvbpsi_AttachPMT( p_program->i_number, (dvbpsi_pmt_callback)PMTCallBack, p_demux );
-            pmt->psi->i_number = p_program->i_number;
+            if( !pmt->b_valid )
+            {
+                PIDInit( pmt, VLC_TRUE, pat->psi );
+                pmt->psi->handle =
+                    dvbpsi_AttachPMT( p_program->i_number,
+                                      (dvbpsi_pmt_callback)PMTCallBack, p_demux );
+                pmt->psi->i_number = p_program->i_number;
 
-            TAB_APPEND( p_sys->i_pmt, p_sys->pmt, pmt );
+                TAB_APPEND( p_sys->i_pmt, p_sys->pmt, pmt );
+            }
         }
     }
     pat->psi->i_version = p_pat->i_version;
 
     dvbpsi_DeletePAT( p_pat );
 }
-