]> git.sesse.net Git - vlc/blobdiff - modules/demux/mpeg/ts.c
* Added 0x80 as MPEG2_MOTO_VIDEO_ES, since some strange Motorola encoders
[vlc] / modules / demux / mpeg / ts.c
index 1e7d79587244f1d37fece776b179f71dd5f5be2e..3b146e6f47099f61bdf7c173374f81b3cc462ece 100644 (file)
@@ -2,7 +2,7 @@
  * mpeg_ts.c : Transport Stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2000-2001 VideoLAN
- * $Id: ts.c,v 1.12 2003/01/07 15:12:48 jobi Exp $
+ * $Id: ts.c,v 1.20 2003/03/18 23:59:07 massiot Exp $
  *
  * Authors: Henri Fallon <henri@via.ecp.fr>
  *          Johan Bilien <jobi@via.ecp.fr>
@@ -54,6 +54,7 @@
 #endif
 
 #include "system.h"
+#include "codecs.h"
 
 /*****************************************************************************
  * Constants
@@ -99,6 +100,11 @@ static void TS_DVBPSI_HandlePMT ( input_thread_t *, dvbpsi_pmt_t * );
     "0.3.x and 0.4. By default VLC assumes you have the latest VLS. In case " \
     "you're using an old version, select this option.")
 
+#define BUGGY_PSI_TEXT N_("buggy PSI")
+#define BUGGY_PSI_LONGTEXT N_( \
+    "If you have a stream whose PSI packets do not feature incremented " \
+    "continuity counters, select this option.")
+
 vlc_module_begin();
 #if defined MODULE_NAME_IS_ts
     set_description( _("ISO 13818-1 MPEG Transport Stream input") );
@@ -109,8 +115,10 @@ vlc_module_begin();
     set_capability( "demux", 170 );
     add_shortcut( "ts_dvbpsi" );
 #endif
+    add_category_hint( N_("Miscellaneous"), NULL, VLC_TRUE );
     add_bool( "vls-backwards-compat", 0, NULL,
-              VLS_BACKWARDS_COMPAT_TEXT, VLS_BACKWARDS_COMPAT_LONGTEXT );
+              VLS_BACKWARDS_COMPAT_TEXT, VLS_BACKWARDS_COMPAT_LONGTEXT, VLC_TRUE );
+    add_bool( "buggy-psi", 0, NULL, BUGGY_PSI_TEXT, BUGGY_PSI_LONGTEXT, VLC_TRUE );
     set_callbacks( Activate, Deactivate );
 vlc_module_end();
 
@@ -190,6 +198,7 @@ static int Activate( vlc_object_t * p_this )
 
     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
     p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
+    p_stream_data->b_buggy_psi = config_GetInt( p_input, "buggy-psi" );
 
 #ifdef MODULE_NAME_IS_ts_dvbpsi
     p_stream_data->p_pat_handle = (dvbpsi_handle *)
@@ -214,6 +223,7 @@ static int Activate( vlc_object_t * p_this )
     p_demux_data->i_psi_type = PSI_IS_PAT;
     p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
     p_demux_data->p_psi_section->b_is_complete = 1;
+    p_demux_data->i_continuity_counter = 0xFF;
 
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
@@ -530,6 +540,7 @@ static void TSDecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
                     p_es_demux->p_psi_section =
                                             malloc( sizeof( psi_section_t ) );
                     p_es_demux->p_psi_section->b_is_complete = 0;
+                    p_es_demux->i_continuity_counter = 0xFF;
                 }
             }
 
@@ -621,6 +632,7 @@ static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
                 /* Add this ES to the program */
                 p_new_es = input_AddES( p_input, p_es->p_pgrm,
                                         (u16)i_pid, sizeof( es_ts_data_t ) );
+                ((es_ts_data_t *)p_new_es->p_demux_data)->i_continuity_counter = 0xFF;
 
                 /* Tell the interface what kind of stream it is and select
                  * the required ones */
@@ -629,11 +641,18 @@ static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
                     {
                         case MPEG1_VIDEO_ES:
                         case MPEG2_VIDEO_ES:
+                        case MPEG2_MOTO_VIDEO_ES:
+                            /* This isn't real, but we don't actually use
+                             * it. */
+                            p_new_es->i_stream_id = 0xE0;
                             p_new_es->i_fourcc = VLC_FOURCC('m','p','g','v');
                             p_new_es->i_cat = VIDEO_ES;
                             break;
                         case MPEG1_AUDIO_ES:
                         case MPEG2_AUDIO_ES:
+                            /* This isn't real, but we don't actually use
+                             * it. */
+                            p_new_es->i_stream_id = 0xC0;
                             p_new_es->i_fourcc = VLC_FOURCC('m','p','g','a');
                             p_new_es->i_cat = AUDIO_ES;
                             break;
@@ -686,17 +705,6 @@ static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
                             p_new_es->i_cat = SPU_ES;
                             break;
 
-                        case 0x10:
-                            p_new_es->i_fourcc = VLC_FOURCC('m','p','4','v');
-                            p_new_es->i_stream_id = 0xfa;   // ???
-                            p_new_es->i_cat = VIDEO_ES;
-                            break;
-                        case 0x11:
-                            p_new_es->i_fourcc = VLC_FOURCC('m','p','4','a');
-                            p_new_es->i_stream_id = 0xfa;   // ???
-                            p_new_es->i_cat = AUDIO_ES;
-                            break;
-
                         default :
                             p_new_es->i_fourcc = 0;
                             p_new_es->i_cat = UNKNOWN_ES;
@@ -733,6 +741,13 @@ static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
                     p_input->pf_set_program( p_input, p_es->p_pgrm );
         }
 
+        /* if the pmt belongs to the currently selected program, we
+         * reselect it to update its ES */
+        else if( p_es->p_pgrm == p_input->stream.p_selected_program )
+        {
+            p_input->pf_set_program( p_input, p_es->p_pgrm );
+        }
+
         /* inform interface that stream has changed */
         p_input->stream.b_changed = 1;
         /*  Remove lock */
@@ -759,20 +774,20 @@ static void TS_DVBPSI_DemuxPSI( input_thread_t  * p_input,
     pgrm_ts_data_t      * p_pgrm_demux_data;
     stream_ts_data_t    * p_stream_demux_data;
 
-    p_es_demux_data = ( es_ts_data_t * ) p_es->p_demux_data;
-    p_stream_demux_data = ( stream_ts_data_t * ) p_input->stream.p_demux_data;
+    p_es_demux_data = (es_ts_data_t *)p_es->p_demux_data;
+    p_stream_demux_data = (stream_ts_data_t *) p_input->stream.p_demux_data;
 
     switch( p_es_demux_data->i_psi_type)
     {
         case PSI_IS_PAT:
             dvbpsi_PushPacket(
-                    ( dvbpsi_handle ) p_stream_demux_data->p_pat_handle,
+                    (dvbpsi_handle)p_stream_demux_data->p_pat_handle,
                     p_data->p_demux_start );
             break;
         case PSI_IS_PMT:
             p_pgrm_demux_data = ( pgrm_ts_data_t * )p_es->p_pgrm->p_demux_data;
             dvbpsi_PushPacket(
-                    ( dvbpsi_handle ) p_pgrm_demux_data->p_pmt_handle,
+                    (dvbpsi_handle)p_pgrm_demux_data->p_pmt_handle,
                     p_data->p_demux_start );
             break;
         default:
@@ -781,6 +796,358 @@ static void TS_DVBPSI_DemuxPSI( input_thread_t  * p_input,
 
     input_DeletePacket( p_input->p_method_data, p_data );
 }
+/*****************************************************************************
+ * MP4 specific functions
+ *****************************************************************************/
+static int  MP4_DescriptorLength( 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 );
+
+    return( i_len );
+}
+static int MP4_GetByte( int *pi_data, uint8_t **pp_data )
+{
+    if( *pi_data > 0 )
+    {
+        int i_b = **pp_data;
+        (*pp_data)++;
+        (*pi_data)--;
+        return( i_b );
+    }
+    else
+    {
+        return( 0 );
+    }
+}
+
+static int MP4_GetWord( int *pi_data, uint8_t **pp_data )
+{
+    int i1, i2;
+    i1 = MP4_GetByte( pi_data, pp_data );
+    i2 = MP4_GetByte( pi_data, pp_data );
+    return( ( i1 << 8 ) | i2 );
+}
+static int MP4_Get3Bytes( int *pi_data, uint8_t **pp_data )
+{
+    int i1, i2, i3;
+    i1 = MP4_GetByte( pi_data, pp_data );
+    i2 = MP4_GetByte( pi_data, pp_data );
+    i3 = MP4_GetByte( pi_data, pp_data );
+    return( ( i1 << 16 ) | ( i2 << 8) | i3 );
+}
+
+static uint32_t MP4_GetDWord( 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 );
+    return( ( i1 << 16 ) | i2 );
+}
+
+static char* MP4_GetURL( int *pi_data, uint8_t **pp_data )
+{
+    char *url;
+    int i_url_len, i;
+
+    i_url_len = MP4_GetByte( pi_data, pp_data );
+    url = malloc( i_url_len + 1 );
+    for( i = 0; i < i_url_len; i++ )
+    {
+        url[i] = MP4_GetByte( pi_data, pp_data );
+    }
+    url[i_url_len] = '\0';
+    return( url );
+}
+
+static void MP4_IODParse( iod_descriptor_t *p_iod, int i_data, uint8_t *p_data )
+{
+    int i;
+    int i_es_index;
+    uint8_t     i_flags;
+    vlc_bool_t  b_url;
+    int         i_iod_length;
+
+    fprintf( stderr, "\n************ IOD ************" );
+    for( i = 0; i < 255; i++ )
+    {
+        p_iod->es_descr[i].b_ok = 0;
+    }
+    i_es_index = 0;
+
+    if( i_data < 3 )
+    {
+        return;
+    }
+
+    p_iod->i_iod_label = MP4_GetByte( &i_data, &p_data );
+    fprintf( stderr, "\n* iod_label:%d", p_iod->i_iod_label );
+    fprintf( stderr, "\n* ===========" );
+    fprintf( stderr, "\n* tag:0x%x", p_data[0] );
+
+    if( MP4_GetByte( &i_data, &p_data ) != 0x02 )
+    {
+        fprintf( stderr, "\n ERR: tag != 0x02" );
+        return;
+    }
+
+    i_iod_length = MP4_DescriptorLength( &i_data, &p_data );
+    fprintf( stderr, "\n* length:%d", i_iod_length );
+    if( i_iod_length > i_data )
+    {
+        i_iod_length = i_data;
+    }
+
+    p_iod->i_od_id = ( MP4_GetByte( &i_data, &p_data ) << 2 );
+    i_flags = MP4_GetByte( &i_data, &p_data );
+    p_iod->i_od_id |= i_flags >> 6;
+    b_url = ( i_flags >> 5  )&0x01;
+
+    fprintf( stderr, "\n* od_id:%d", p_iod->i_od_id );
+    fprintf( stderr, "\n* url flag:%d", b_url );
+    fprintf( stderr, "\n* includeInlineProfileLevel flag:%d", ( i_flags >> 4 )&0x01 );
+
+    if( b_url )
+    {
+        p_iod->psz_url = MP4_GetURL( &i_data, &p_data );
+        fprintf( stderr, "\n* url string:%s", p_iod->psz_url );
+        fprintf( stderr, "\n*****************************\n" );
+        return;
+    }
+    else
+    {
+        p_iod->psz_url = NULL;
+    }
+
+    p_iod->i_ODProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
+    p_iod->i_sceneProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
+    p_iod->i_audioProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
+    p_iod->i_visualProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
+    p_iod->i_graphicsProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
+
+    fprintf( stderr, "\n* ODProfileLevelIndication:%d", p_iod->i_ODProfileLevelIndication );
+    fprintf( stderr, "\n* sceneProfileLevelIndication:%d", p_iod->i_sceneProfileLevelIndication );
+    fprintf( stderr, "\n* audioProfileLevelIndication:%d", p_iod->i_audioProfileLevelIndication );
+    fprintf( stderr, "\n* visualProfileLevelIndication:%d", p_iod->i_visualProfileLevelIndication );
+    fprintf( stderr, "\n* graphicsProfileLevelIndication:%d", p_iod->i_graphicsProfileLevelIndication );
+
+
+    while( i_data > 0 && i_es_index < 255)
+    {
+        int i_tag, i_length;
+        int     i_data_sav;
+        uint8_t *p_data_sav;
+
+        i_tag = MP4_GetByte( &i_data, &p_data );
+        i_length = MP4_DescriptorLength( &i_data, &p_data );
+
+        i_data_sav = i_data;
+        p_data_sav = p_data;
+
+        i_data = i_length;
+
+        switch( i_tag )
+        {
+            case 0x03:
+                {
+#define es_descr    p_iod->es_descr[i_es_index]
+                    int i_decoderConfigDescr_length;
+                    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 );
+                    i_flags = MP4_GetByte( &i_data, &p_data );
+                    es_descr.b_streamDependenceFlag = ( i_flags >> 7 )&0x01;
+                    b_url = ( i_flags >> 6 )&0x01;
+                    es_descr.b_OCRStreamFlag = ( i_flags >> 5 )&0x01;
+                    es_descr.i_streamPriority = i_flags & 0x1f;
+                    fprintf( stderr, "\n*   * streamDependenceFlag:%d", es_descr.b_streamDependenceFlag );
+                    fprintf( stderr, "\n*   * OCRStreamFlag:%d", es_descr.b_OCRStreamFlag );
+                    fprintf( stderr, "\n*   * streamPriority:%d", es_descr.i_streamPriority );
+
+                    if( es_descr.b_streamDependenceFlag )
+                    {
+                        es_descr.i_dependOn_es_id = MP4_GetWord( &i_data, &p_data );
+                        fprintf( stderr, "\n*   * dependOn_es_id:%d", es_descr.i_dependOn_es_id );
+                    }
+
+                    if( b_url )
+                    {
+                        es_descr.psz_url = MP4_GetURL( &i_data, &p_data );
+                        fprintf( stderr, "\n* url string:%s", es_descr.psz_url );
+                    }
+                    else
+                    {
+                        es_descr.psz_url = NULL;
+                    }
+
+                    if( es_descr.b_OCRStreamFlag )
+                    {
+                        es_descr.i_OCR_es_id = MP4_GetWord( &i_data, &p_data );
+                        fprintf( stderr, "\n*   * OCR_es_id:%d", es_descr.i_OCR_es_id );
+                    }
+
+                    if( MP4_GetByte( &i_data, &p_data ) != 0x04 )
+                    {
+                        fprintf( stderr, "\n* ERR missing DecoderConfigDescr" );
+                        es_descr.b_ok = 0;
+                        break;
+                    }
+                    i_decoderConfigDescr_length = MP4_DescriptorLength( &i_data, &p_data );
+
+                    fprintf( stderr, "\n*   - DecoderConfigDesc length:%d", i_decoderConfigDescr_length );
+#define dec_descr   es_descr.dec_descr
+                    dec_descr.i_objectTypeIndication = MP4_GetByte( &i_data, &p_data );
+                    i_flags = MP4_GetByte( &i_data, &p_data );
+                    dec_descr.i_streamType = i_flags >> 2;
+                    dec_descr.b_upStream = ( i_flags >> 1 )&0x01;
+                    dec_descr.i_bufferSizeDB = MP4_Get3Bytes( &i_data, &p_data );
+                    dec_descr.i_maxBitrate = MP4_GetDWord( &i_data, &p_data );
+                    dec_descr.i_avgBitrate = MP4_GetDWord( &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 );
+                    fprintf( stderr, "\n*     * bufferSizeDB:%d", dec_descr.i_bufferSizeDB );
+                    fprintf( stderr, "\n*     * maxBitrate:%d", dec_descr.i_maxBitrate );
+                    fprintf( stderr, "\n*     * avgBitrate:%d", dec_descr.i_avgBitrate );
+                    if( i_decoderConfigDescr_length > 13 && MP4_GetByte( &i_data, &p_data ) == 0x05 )
+                    {
+                        int i;
+                        dec_descr.i_decoder_specific_info_len =
+                            MP4_DescriptorLength( &i_data, &p_data );
+                        if( dec_descr.i_decoder_specific_info_len > 0 )
+                        {
+                            dec_descr.p_decoder_specific_info =
+                                malloc( dec_descr.i_decoder_specific_info_len );
+                        }
+                        for( i = 0; i < dec_descr.i_decoder_specific_info_len; i++ )
+                        {
+                            dec_descr.p_decoder_specific_info[i] = MP4_GetByte( &i_data, &p_data );
+                        }
+                    }
+                    else
+                    {
+                        dec_descr.i_decoder_specific_info_len = 0;
+                        dec_descr.p_decoder_specific_info = NULL;
+                    }
+                }
+#undef  dec_descr
+#define sl_descr    es_descr.sl_descr
+                {
+                    int i_SLConfigDescr_length;
+                    int i_predefined;
+
+                    if( MP4_GetByte( &i_data, &p_data ) != 0x06 )
+                    {
+                        fprintf( stderr, "\n* ERR missing SLConfigDescr" );
+                        es_descr.b_ok = 0;
+                        break;
+                    }
+                    i_SLConfigDescr_length = MP4_DescriptorLength( &i_data, &p_data );
+
+                    fprintf( stderr, "\n*   - SLConfigDescr length:%d", i_SLConfigDescr_length );
+                    i_predefined = MP4_GetByte( &i_data, &p_data );
+                    fprintf( stderr, "\n*     * i_predefined:0x%x", i_predefined  );
+                    switch( i_predefined )
+                    {
+                        case 0x01:
+                            {
+                                sl_descr.b_useAccessUnitStartFlag   = 0;
+                                sl_descr.b_useAccessUnitEndFlag     = 0;
+                                sl_descr.b_useRandomAccessPointFlag = 0;
+                                //sl_descr.b_useRandomAccessUnitsOnlyFlag = 0;
+                                sl_descr.b_usePaddingFlag           = 0;
+                                sl_descr.b_useTimeStampsFlags       = 0;
+                                sl_descr.b_useIdleFlag              = 0;
+                                sl_descr.b_durationFlag     = 0;    // FIXME FIXME
+                                sl_descr.i_timeStampResolution      = 1000;
+                                sl_descr.i_OCRResolution    = 0;    // FIXME FIXME
+                                sl_descr.i_timeStampLength          = 32;
+                                sl_descr.i_OCRLength        = 0;    // FIXME FIXME
+                                sl_descr.i_AU_Length                = 0;
+                                sl_descr.i_instantBitrateLength= 0; // FIXME FIXME
+                                sl_descr.i_degradationPriorityLength= 0;
+                                sl_descr.i_AU_seqNumLength          = 0;
+                                sl_descr.i_packetSeqNumLength       = 0;
+                                if( sl_descr.b_durationFlag )
+                                {
+                                    sl_descr.i_timeScale            = 0;    // FIXME FIXME
+                                    sl_descr.i_accessUnitDuration   = 0;    // FIXME FIXME
+                                    sl_descr.i_compositionUnitDuration= 0;    // FIXME FIXME
+                                }
+                                if( !sl_descr.b_useTimeStampsFlags )
+                                {
+                                    sl_descr.i_startDecodingTimeStamp   = 0;    // FIXME FIXME
+                                    sl_descr.i_startCompositionTimeStamp= 0;    // FIXME FIXME
+                                }
+                            }
+                            break;
+                        default:
+                            fprintf( stderr, "\n* ERR unsupported SLConfigDescr predefined" );
+                            es_descr.b_ok = 0;
+                            break;
+                    }
+                }
+                break;
+#undef  sl_descr
+#undef  es_descr
+            default:
+                fprintf( stderr, "\n* - OD tag:0x%x length:%d (Unsupported)", i_tag, i_length );
+                break;
+        }
+
+        p_data = p_data_sav + i_length;
+        i_data = i_data_sav - i_length;
+        i_es_index++;
+    }
+
+
+    fprintf( stderr, "\n*****************************\n" );
+}
+
+static void MP4_IODClean( iod_descriptor_t *p_iod )
+{
+    int i;
+
+    if( p_iod->psz_url )
+    {
+        free( p_iod->psz_url );
+        p_iod->psz_url = NULL;
+        return;
+    }
+
+    for( 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 );
+                es_descr.psz_url = NULL;
+            }
+            else
+            {
+                if( es_descr.dec_descr.p_decoder_specific_info != NULL )
+                {
+                    free( es_descr.dec_descr.p_decoder_specific_info );
+                    es_descr.dec_descr.p_decoder_specific_info = NULL;
+                    es_descr.dec_descr.i_decoder_specific_info_len = 0;
+                }
+            }
+        }
+        es_descr.b_ok = 0;
+#undef  es_descr
+    }
+}
 
 /*****************************************************************************
  * HandlePAT: will treat a PAT returned by dvbpsi
@@ -799,12 +1166,20 @@ static void TS_DVBPSI_HandlePAT( input_thread_t * p_input,
 
     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
 
-    if ( !p_new_pat->b_current_next ||
+    if ( ( p_new_pat->b_current_next && ( p_new_pat->i_version != p_stream_data->i_pat_version ) ) ||
             p_stream_data->i_pat_version == PAT_UNINITIALIZED  )
     {
         /* Delete all programs */
         while( p_input->stream.i_pgrm_number )
         {
+            pgrm_ts_data_t *p_pgrm_demux_old =
+                (pgrm_ts_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
+
+            if( p_pgrm_demux_old->b_mpeg4 )
+            {
+                MP4_IODClean( &p_pgrm_demux_old->iod );
+            }
+
             input_DelProgram( p_input, p_input->stream.pp_programs[0] );
         }
 
@@ -840,6 +1215,7 @@ static void TS_DVBPSI_HandlePAT( input_thread_t * p_input,
                 }
 
                 p_es_demux->p_psi_section->b_is_complete = 0;
+                p_es_demux->i_continuity_counter = 0xFF;
 
                 /* Create a PMT decoder */
                 p_pgrm_demux->p_pmt_handle = (dvbpsi_handle *)
@@ -863,6 +1239,7 @@ static void TS_DVBPSI_HandlePAT( input_thread_t * p_input,
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 }
 
+
 /*****************************************************************************
  * HandlePMT: will treat a PMT returned by dvbpsi
  *****************************************************************************/
@@ -888,9 +1265,19 @@ static void TS_DVBPSI_HandlePMT( input_thread_t * p_input,
     p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
     p_pgrm_demux->i_pcr_pid = p_new_pmt->i_pcr_pid;
 
-    if( !p_new_pmt->b_current_next ||
+    if( ( p_new_pmt->b_current_next && ( p_new_pmt->i_version != p_pgrm_demux->i_pmt_version ) ) ||
             p_pgrm_demux->i_pmt_version == PMT_UNINITIALIZED )
     {
+        dvbpsi_descriptor_t *p_dr = p_new_pmt->p_first_descriptor;
+        /* IOD */
+        while( p_dr && ( p_dr->i_tag != 0x1d ) )
+            p_dr = p_dr->p_next;
+        if( p_dr)
+        {
+            msg_Warn( p_input, "found IOD descriptor" );
+            MP4_IODParse( &p_pgrm_demux->iod, p_dr->i_length, p_dr->p_data );
+        }
+
         p_es = p_new_pmt->p_first_es;
         while( p_es )
         {
@@ -903,11 +1290,13 @@ static void TS_DVBPSI_HandlePMT( input_thread_t * p_input,
                 p_input->b_error = 1;
                 return;
             }
+            ((es_ts_data_t *)p_new_es->p_demux_data)->i_continuity_counter = 0xFF;
 
             switch( p_es->i_type )
             {
                 case MPEG1_VIDEO_ES:
                 case MPEG2_VIDEO_ES:
+                case MPEG2_MOTO_VIDEO_ES:
                     p_new_es->i_fourcc = VLC_FOURCC('m','p','g','v');
                     p_new_es->i_cat = VIDEO_ES;
                     break;
@@ -963,17 +1352,222 @@ static void TS_DVBPSI_HandlePMT( input_thread_t * p_input,
                     p_new_es->i_cat = AUDIO_ES;
                     p_new_es->i_stream_id = 0xBD;
                     break;
-
-                case 0xfa:
+                case MPEG4_VIDEO_ES:
                     p_new_es->i_fourcc = VLC_FOURCC('m','p','4','v');
                     p_new_es->i_cat = VIDEO_ES;
+                    p_new_es->i_stream_id = 0xfa;
+                    break;
+                case MPEG4_AUDIO_ES:
+                    p_new_es->i_fourcc = VLC_FOURCC('m','p','4','a');
+                    p_new_es->i_cat = AUDIO_ES;
+                    p_new_es->i_stream_id = 0xfa;
+                    break;
+                case MSCODEC_VIDEO_ES:
+                    p_new_es->i_fourcc = VLC_FOURCC(0,0,0,0);   // fixed later
+                    p_new_es->i_cat = VIDEO_ES;
+                    p_new_es->i_stream_id = 0xa0;
                     break;
-
                 default:
                     p_new_es->i_fourcc = 0;
                     p_new_es->i_cat = UNKNOWN_ES;
             }
 
+            if( p_es->i_type == MPEG4_VIDEO_ES || p_es->i_type == MPEG4_AUDIO_ES )
+            {
+                /* mpeg4 stream, search sl_descriptor */
+                dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;
+                es_ts_data_t        *p_es_demux =
+                                        (es_ts_data_t*)p_new_es->p_demux_data;
+
+                while( p_dr && ( p_dr->i_tag != 0x1f ) )
+                    p_dr = p_dr->p_next;
+                if( p_dr && p_dr->i_length == 2 )
+                {
+                    int i_es_descr_index;
+
+                    p_es_demux->i_es_id =
+                        ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
+                    p_es_demux->p_es_descr = NULL;
+
+                    msg_Warn( p_input, "found SL_descriptor" );
+                    for( i_es_descr_index = 0; i_es_descr_index < 255; i_es_descr_index++ )
+                    {
+                        if( p_pgrm_demux->iod.es_descr[i_es_descr_index].b_ok &&
+                            p_pgrm_demux->iod.es_descr[i_es_descr_index].i_es_id == p_es_demux->i_es_id )
+                        {
+                            p_es_demux->p_es_descr = &p_pgrm_demux->iod.es_descr[i_es_descr_index];
+                            break;
+                        }
+                    }
+                }
+                if( p_es_demux->p_es_descr != NULL )
+                {
+                    vlc_fourcc_t i_fourcc;
+                    int          i_cat;
+                    p_es_demux->b_mpeg4 = 1;
+
+                    /* fix fourcc */
+                    switch( p_es_demux->p_es_descr->dec_descr.i_streamType )
+                    {
+                        case 0x04:  /* VisualStream */
+                            i_cat = VIDEO_ES;
+                            switch( p_es_demux->p_es_descr->dec_descr.i_objectTypeIndication )
+                            {
+                                case 0x20:
+                                    i_fourcc = VLC_FOURCC('m','p','4','v');     // mpeg4
+                                    break;
+                                case 0x60:
+                                case 0x61:
+                                case 0x62:
+                                case 0x63:
+                                case 0x64:
+                                case 0x65:
+                                    i_fourcc = VLC_FOURCC( 'm','p','g','v' );   // mpeg2
+                                    break;
+                                case 0x6a:
+                                    i_fourcc = VLC_FOURCC( 'm','p','g','v' );   // mpeg1
+                                    break;
+                                case 0x6c:
+                                    i_fourcc = VLC_FOURCC( 'j','p','e','g' );   // mpeg1
+                                    break;
+                                default:
+                                    i_fourcc = 0;
+                                    break;
+                            }
+                            break;
+                        case 0x05:  /* AudioStream */
+                            i_cat = AUDIO_ES;
+                            switch( p_es_demux->p_es_descr->dec_descr.i_objectTypeIndication )
+                            {
+                                case 0x40:
+                                    i_fourcc = VLC_FOURCC('m','p','4','a');     // mpeg4
+                                    break;
+                                case 0x66:
+                                case 0x67:
+                                case 0x68:
+                                    i_fourcc = VLC_FOURCC('m','p','4','a');     // mpeg2 aac
+                                    break;
+                                case 0x69:
+                                    i_fourcc = VLC_FOURCC('m','p','g','a');     // mpeg2
+                                    break;
+                                case 0x6b:
+                                    i_fourcc = VLC_FOURCC('m','p','g','a');     // mpeg1
+                                    break;
+                                default:
+                                    i_fourcc = 0;
+                                    break;
+                            }
+                            break;
+                        default:
+                            i_cat = UNKNOWN_ES;
+                            i_fourcc = 0;
+                            break;
+                    }
+
+                    p_new_es->i_fourcc = i_fourcc;
+                    p_new_es->i_cat    = i_cat;
+                    switch( i_cat )
+                    {
+                        case VIDEO_ES:
+                            {
+                                int i_size;
+                                BITMAPINFOHEADER *p_bih;
+
+                                i_size = sizeof( BITMAPINFOHEADER ) +
+                                                 p_es_demux->p_es_descr->dec_descr.i_decoder_specific_info_len;
+                                p_new_es->p_bitmapinfoheader = (void*)p_bih = malloc( i_size );
+                                p_bih->biSize = i_size;
+                                p_bih->biWidth = 0;
+                                p_bih->biHeight = 0;
+                                p_bih->biPlanes = 1;
+                                p_bih->biBitCount = 0;
+                                p_bih->biCompression = 0;
+                                p_bih->biSizeImage = 0;
+                                p_bih->biXPelsPerMeter = 0;
+                                p_bih->biYPelsPerMeter = 0;
+                                p_bih->biClrUsed = 0;
+                                p_bih->biClrImportant = 0;
+                                memcpy( &p_bih[1],
+                                        p_es_demux->p_es_descr->dec_descr.p_decoder_specific_info,
+                                        p_es_demux->p_es_descr->dec_descr.i_decoder_specific_info_len );
+                            }
+                            break;
+                        case AUDIO_ES:
+                            {
+                                int i_size;
+                                WAVEFORMATEX *p_wf;
+
+                                i_size = sizeof( WAVEFORMATEX ) +
+                                                 p_es_demux->p_es_descr->dec_descr.i_decoder_specific_info_len;
+                                p_new_es->p_waveformatex = (void*)p_wf = malloc( i_size );
+                                p_wf->wFormatTag = 0xffff;
+                                p_wf->nChannels = 0;
+                                p_wf->nSamplesPerSec = 0;
+                                p_wf->nAvgBytesPerSec = 0;
+                                p_wf->nBlockAlign = 1;
+                                p_wf->wBitsPerSample = 0;
+                                p_wf->cbSize = p_es_demux->p_es_descr->dec_descr.i_decoder_specific_info_len;
+                                memcpy( &p_wf[1],
+                                        p_es_demux->p_es_descr->dec_descr.p_decoder_specific_info,
+                                        p_es_demux->p_es_descr->dec_descr.i_decoder_specific_info_len );
+                            }
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                else
+                {
+                    msg_Warn( p_input, "mpeg4 stream without (valid) sl_descriptor" );
+                    p_es_demux->b_mpeg4 = 0;
+                }
+
+            }
+            else if( p_es->i_type == MSCODEC_VIDEO_ES )
+            {
+                /* crapy ms codec stream, search private descriptor */
+                dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;
+                es_ts_data_t        *p_es_demux =
+                                        (es_ts_data_t*)p_new_es->p_demux_data;
+
+                while( p_dr && ( p_dr->i_tag != 0xa0 ) )
+                    p_dr = p_dr->p_next;
+                if( p_dr && p_dr->i_length >= 8 )
+                {
+                    int i_size;
+                    int i_bih_size;
+                    BITMAPINFOHEADER *p_bih;
+
+                    p_new_es->i_fourcc = ( p_dr->p_data[0] << 24 )| ( p_dr->p_data[1] << 16 )|
+                                         ( p_dr->p_data[2] <<  8 )| ( p_dr->p_data[3] );
+
+                    i_bih_size = ( ( p_dr->p_data[8] << 8)|( p_dr->p_data[9] ) );
+                    i_size = sizeof( BITMAPINFOHEADER ) + i_bih_size;
+
+                    p_new_es->p_bitmapinfoheader = (void*)p_bih = malloc( i_size );
+                    p_bih->biSize = i_size;
+                    p_bih->biWidth = ( p_dr->p_data[4] << 8 )|p_dr->p_data[5];
+                    p_bih->biHeight = ( p_dr->p_data[6] << 8 )|p_dr->p_data[7];
+                    p_bih->biPlanes = 1;
+                    p_bih->biBitCount = 0;
+                    p_bih->biCompression = 0;
+                    p_bih->biSizeImage = 0;
+                    p_bih->biXPelsPerMeter = 0;
+                    p_bih->biYPelsPerMeter = 0;
+                    p_bih->biClrUsed = 0;
+                    p_bih->biClrImportant = 0;
+                    memcpy( &p_bih[1],
+                            &p_dr->p_data[10],
+                            i_bih_size );
+                }
+                else
+                {
+                    msg_Warn( p_input, "private ms-codec stream without bih private sl_descriptor" );
+                    p_new_es->i_fourcc = 0;
+                    p_new_es->i_cat = UNKNOWN_ES;
+                }
+            }
+
             if(    ( p_new_es->i_cat == AUDIO_ES )
                 || (p_new_es->i_cat == SPU_ES ) )
             {
@@ -1019,6 +1613,9 @@ static void TS_DVBPSI_HandlePMT( input_thread_t * p_input,
                     case A52B_AUDIO_ES:
                         strcat( p_new_es->psz_desc, " (A52)" );
                         break;
+                    case MPEG4_AUDIO_ES:
+                        strcat( p_new_es->psz_desc, " (aac)" );
+                        break;
                 }
             }