]> git.sesse.net Git - vlc/blobdiff - modules/demux/mpeg/system.c
* include/vlc_common.h:
[vlc] / modules / demux / mpeg / system.c
index c70d9514df4fb8470d86cfb46afffd0b07982389..245cb3aeaeff65ec675c2bcc0052bbe023d037c8 100644 (file)
@@ -2,7 +2,7 @@
  * system.c: helper module for TS, PS and PES management
  *****************************************************************************
  * Copyright (C) 1998-2002 VideoLAN
- * $Id: system.c,v 1.1 2002/08/07 00:29:36 sam Exp $
+ * $Id: system.c,v 1.18 2003/10/25 00:49:14 sam Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Michel Lespinasse <walken@via.ecp.fr>
@@ -14,7 +14,7 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -29,8 +29,6 @@
  * Preamble
  *****************************************************************************/
 #include <stdlib.h>
-#include <string.h>                                    /* memcpy(), memset() */
-#include <sys/types.h>                                              /* off_t */
 
 #include <vlc/vlc.h>
 #include <vlc/input.h>
@@ -87,10 +85,10 @@ static int Activate ( vlc_object_t *p_this )
 static inline size_t MoveChunk( byte_t * p_dest, data_packet_t ** pp_data_src,
                                 byte_t ** pp_src, size_t i_buf_len )
 {
-    ptrdiff_t           i_available;
+    size_t i_available;
 
-    if( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
-            >= i_buf_len )
+    i_available = (ptrdiff_t)((*pp_data_src)->p_payload_end - *pp_src);
+    if( i_available >= i_buf_len )
     {
         if( p_dest != NULL )
             memcpy( p_dest, *pp_src, i_buf_len );
@@ -99,7 +97,7 @@ static inline size_t MoveChunk( byte_t * p_dest, data_packet_t ** pp_data_src,
     }
     else
     {
-        size_t          i_init_len = i_buf_len;
+        size_t i_init_len = i_buf_len;
 
         do
         {
@@ -114,9 +112,10 @@ static inline size_t MoveChunk( byte_t * p_dest, data_packet_t ** pp_data_src,
                 return( i_init_len - i_buf_len );
             }
             *pp_src = (*pp_data_src)->p_payload_start;
+
+            i_available = (ptrdiff_t)((*pp_data_src)->p_payload_end - *pp_src);
         }
-        while( (i_available = (*pp_data_src)->p_payload_end - *pp_src)
-                <= i_buf_len );
+        while( i_available <= i_buf_len );
 
         if( i_buf_len )
         {
@@ -177,7 +176,7 @@ static void ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
     }
     else
     {
-        int i_pes_header_size, i_payload_size;
+        unsigned int i_pes_header_size, i_payload_size;
 
         if ( p_es->i_pes_real_size &&
              (p_es->i_pes_real_size != p_pes->i_pes_size) )
@@ -187,7 +186,7 @@ static void ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
             msg_Warn( p_input, "packet corrupted, PES sizes do not match" );
         }
 
-        switch( p_es->i_stream_id )
+        switch( p_header[3] )
         {
         case 0xBC:  /* Program stream map */
         case 0xBE:  /* Padding */
@@ -215,7 +214,7 @@ static void ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                 i_max_len = MoveChunk( p_full_header, &p_data, &p_byte, 12 );
                 if( i_max_len < 2 )
                 {
-                    msg_Warn( p_input, 
+                    msg_Warn( p_input,
                               "PES packet too short to have a MPEG-2 header" );
                     input_DeletePES( p_input->p_method_data,
                                             p_pes );
@@ -363,17 +362,20 @@ static void ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
             break;
         }
 
-        if( p_es->i_stream_id == 0xbd )
+        /* Welcome to the kludge area ! --Meuuh */
+        if ( p_es->i_fourcc == VLC_FOURCC('a','5','2','b') )
         {
-            /* With private stream 1, the first byte of the payload
-             * is a stream_private_id, so skip it. */
-            i_pes_header_size++;
+            /* With A/52 audio, we need to skip the first 4 bytes */
+            i_pes_header_size += 4;
         }
 
-        if( p_es->i_fourcc == VLC_FOURCC('a','5','2',' ') )
+        if ( p_es->i_fourcc == VLC_FOURCC('l','p','c','b')
+              || p_es->i_fourcc == VLC_FOURCC('s','p','u','b')
+              || p_es->i_fourcc == VLC_FOURCC('d','t','s','b')
+              || p_es->i_fourcc == VLC_FOURCC('s','d','d','b') )
         {
-            /* With A52 audio, we need to skip first 3 bytes */
-            i_pes_header_size += 3;
+            /* stream_private_id */
+            i_pes_header_size += 1;
         }
 
         /* Now we've parsed the header, we just have to indicate in some
@@ -477,19 +479,23 @@ static void GatherPES( input_thread_t * p_input, data_packet_t * p_data,
             }
             p_pes->i_rate = p_input->stream.control.i_rate;
             p_pes->p_first = p_data;
-            
+
             /* If the PES header fits in the first data packet, we can
              * already set p_gather->i_pes_real_size. */
             if( p_data->p_payload_end - p_data->p_payload_start
                     >= PES_HEADER_SIZE )
             {
-                p_es->i_pes_real_size = ((u16)p_data->p_payload_start[4] << 8)
-                                         + p_data->p_payload_start[5] + 6;
+                p_es->i_pes_real_size = ((uint16_t)p_data->p_payload_start[4] << 8)
+                                         + p_data->p_payload_start[5];
+                if ( p_es->i_pes_real_size )
+                {
+                    p_es->i_pes_real_size += 6;
+                }
             }
             else
-            { 
+            {
                 p_es->i_pes_real_size = 0;
-            } 
+            }
         }
         else
         {
@@ -503,10 +509,16 @@ static void GatherPES( input_thread_t * p_input, data_packet_t * p_data,
         /* Size of the payload carried in the data packet */
         p_pes->i_pes_size += (p_data->p_payload_end
                                  - p_data->p_payload_start);
-    
+
         /* We can check if the packet is finished */
-        if( p_pes->i_pes_size == p_es->i_pes_real_size )
+        if( p_es->i_pes_real_size  && p_pes->i_pes_size >= p_es->i_pes_real_size )
         {
+            if( p_pes->i_pes_size > p_es->i_pes_real_size )
+            {
+                msg_Warn( p_input,
+                          "Oversized PES packet for PID %d: expected %d, actual %d",
+                          p_es->i_id, p_es->i_pes_real_size, p_pes->i_pes_size );
+            }
             /* The packet is finished, parse it */
             ParsePES( p_input, p_es );
         }
@@ -522,9 +534,9 @@ static void GatherPES( input_thread_t * p_input, data_packet_t * p_data,
 /*****************************************************************************
  * GetID: Get the ID of a stream
  *****************************************************************************/
-static u16 GetID( data_packet_t * p_data )
+static uint16_t GetID( data_packet_t * p_data )
 {
-    u16         i_id;
+    uint16_t i_id;
 
     i_id = p_data->p_demux_start[3];                            /* stream_id */
     if( i_id == 0xBD )
@@ -548,8 +560,8 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
                  (stream_ps_data_t *)p_input->stream.p_demux_data;
     byte_t *            p_byte;
     byte_t *            p_end;
-    int                 i;
-    int                 i_new_es_number = 0;
+    unsigned int        i;
+    unsigned int        i_new_es_number = 0;
 
     if( p_data->p_demux_start + 10 > p_data->p_payload_end )
     {
@@ -593,7 +605,7 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
     while( p_byte + 4 <= p_end )
     {
         es_descriptor_t *   p_es = NULL;
-        u8                  i_stream_id = p_byte[1];
+        uint8_t             i_stream_id = p_byte[1];
         /* FIXME: there will be a problem with private streams... (same
          * stream_id) */
 
@@ -632,37 +644,43 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
          * so that we can close them more easily at the end. */
         if( p_es == NULL )
         {
-            p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
-                                i_stream_id, 0 );
+            int i_fourcc, i_cat;
+
             switch( p_byte[0] )
             {
             case MPEG1_VIDEO_ES:
             case MPEG2_VIDEO_ES:
-                p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
-                p_es->i_cat = VIDEO_ES;
+            case MPEG2_MOTO_VIDEO_ES:
+                i_fourcc = VLC_FOURCC('m','p','g','v');
+                i_cat = VIDEO_ES;
                 break;
             case DVD_SPU_ES:
-                p_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
-                p_es->i_cat = SPU_ES;
+                i_fourcc = VLC_FOURCC('s','p','u','b');
+                i_cat = SPU_ES;
                 break;
             case MPEG1_AUDIO_ES:
             case MPEG2_AUDIO_ES:
-                p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
-                p_es->i_cat = AUDIO_ES;
+                i_fourcc = VLC_FOURCC('m','p','g','a');
+                i_cat = AUDIO_ES;
                 break;
             case A52_AUDIO_ES:
-                p_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
-                p_es->i_cat = AUDIO_ES;
+                i_fourcc = VLC_FOURCC('a','5','2','b');
+                i_cat = AUDIO_ES;
                 break;
             case LPCM_AUDIO_ES:
-                p_es->i_fourcc = VLC_FOURCC('l','p','c','m');
-                p_es->i_cat = AUDIO_ES;
+                i_fourcc = VLC_FOURCC('l','p','c','b');
+                i_cat = AUDIO_ES;
                 break;
             default:
-                p_es->i_fourcc = 0;
+                i_cat = UNKNOWN_ES;
+                i_fourcc = 0;
                 break;
             }
 
+            p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
+                                i_stream_id, i_cat, NULL, 0 );
+            p_es->i_fourcc = i_fourcc;
+
             /* input_AddES has inserted the new element at the end. */
             p_input->stream.pp_programs[0]->pp_es[
                 p_input->stream.pp_programs[0]->i_es_number ]
@@ -697,7 +715,7 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
     {                                                                       \
         return( -1 );                                                       \
     }                                                                       \
-    else if( i_error < SIZE )                                               \
+    else if( (size_t)i_error < SIZE )                                       \
     {                                                                       \
         /* EOF */                                                           \
         return( 0 );                                                        \
@@ -761,6 +779,7 @@ static ssize_t ReadPS( input_thread_t * p_input, data_packet_t ** pp_data )
             else
             {
                 msg_Err( p_input, "unable to determine stream type" );
+                p_input->p_current_data++;
                 return( -1 );
             }
         }
@@ -799,15 +818,15 @@ static ssize_t ReadPS( input_thread_t * p_input, data_packet_t ** pp_data )
 static es_descriptor_t * ParsePS( input_thread_t * p_input,
                                   data_packet_t * p_data )
 {
-    u32                 i_code;
+    uint32_t            i_code;
     es_descriptor_t *   p_es = NULL;
 
     i_code = p_data->p_demux_start[3];
 
     if( i_code > 0xBC ) /* ES start code */
     {
-        u16                 i_id;
-        int                 i_dummy;
+        uint16_t            i_id;
+        unsigned int        i_dummy;
 
         /* This is a PES packet. Find out if we want it or not. */
         i_id = GetID( p_data );
@@ -829,6 +848,7 @@ static es_descriptor_t * ParsePS( input_thread_t * p_input,
         }
         else
         {
+            vlc_bool_t b_auto_spawn = VLC_FALSE;
             stream_ps_data_t * p_demux =
               (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
 
@@ -837,86 +857,107 @@ static es_descriptor_t * ParsePS( input_thread_t * p_input,
 
             if( p_es == NULL && !p_demux->b_has_PSM )
             {
-                p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
-                                    i_id, 0 );
-                if( p_es != NULL )
-                {
-                    p_es->i_stream_id = p_data->p_demux_start[3];
+                int i_fourcc, i_cat;
 
-                    /* Set stream type and auto-spawn. */
-                    if( (i_id & 0xF0) == 0xE0 )
-                    {
-                        /* MPEG video */
-                        p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
-                        p_es->i_cat = VIDEO_ES;
+                /* Set stream type and auto-spawn. */
+                if( (i_id & 0xF0) == 0xE0 )
+                {
+                    /* MPEG video */
+                    i_fourcc = VLC_FOURCC('m','p','g','v');
+                    i_cat = VIDEO_ES;
 #ifdef AUTO_SPAWN
-                        if( !p_input->stream.b_seekable )
-                            input_SelectES( p_input, p_es );
+                    if( !p_input->stream.b_seekable ) b_auto_spawn = VLC_TRUE;
 #endif
-                    }
-                    else if( (i_id & 0xE0) == 0xC0 )
-                    {
-                        /* MPEG audio */
-                        p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
-                        p_es->i_cat = AUDIO_ES;
+                }
+                else if( (i_id & 0xE0) == 0xC0 )
+                {
+                    /* MPEG audio */
+                    i_fourcc = VLC_FOURCC('m','p','g','a');
+                    i_cat = AUDIO_ES;
 #ifdef AUTO_SPAWN
-                        if( !p_input->stream.b_seekable )
-                        if( config_GetInt( p_input, "audio-channel" )
-                                == (p_es->i_id & 0x1F) ||
-                            ( config_GetInt( p_input, "audio-channel" ) < 0
-                              && !(p_es->i_id & 0x1F) ) )
-                        switch( config_GetInt( p_input, "audio-type" ) )
-                        {
-                        case -1:
-                        case REQUESTED_MPEG:
-                            input_SelectES( p_input, p_es );
-                        }
-#endif
-                    }
-                    else if( (i_id & 0xF0FF) == 0x80BD )
+                    if( !p_input->stream.b_seekable )
+                    if( config_GetInt( p_input, "audio-channel" )
+                            == (i_id & 0x1F) ||
+                        ( config_GetInt( p_input, "audio-channel" ) < 0
+                          && !(i_id & 0x1F) ) )
+                    switch( config_GetInt( p_input, "audio-type" ) )
                     {
-                        /* A52 audio (0x80->0x8F) */
-                        p_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
-                        p_es->i_cat = AUDIO_ES;
-#ifdef AUTO_SPAWN
-                        if( !p_input->stream.b_seekable )
-                        if( config_GetInt( p_input, "audio-channel" )
-                                == ((p_es->i_id & 0xF00) >> 8) ||
-                            ( config_GetInt( p_input, "audio-channel" ) < 0
-                              && !((p_es->i_id & 0xF00) >> 8)) )
-                        switch( config_GetInt( p_input, "audio-type" ) )
-                        {
-                        case -1:
-                        case REQUESTED_A52:
-                            input_SelectES( p_input, p_es );
-                        }
-#endif
+                    case -1:
+                    case REQUESTED_MPEG:
+                        b_auto_spawn = VLC_TRUE;
                     }
-                    else if( (i_id & 0xE0FF) == 0x20BD )
-                    {
-                        /* Subtitles video (0x20->0x3F) */
-                        p_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
-                        p_es->i_cat = SPU_ES;
-#ifdef AUTO_SPAWN
-                        if( config_GetInt( p_input, "spu-channel" )
-                                == ((p_es->i_id & 0x1F00) >> 8) )
-                        {
-                            if( !p_input->stream.b_seekable )
-                                input_SelectES( p_input, p_es );
-                        }
 #endif
+                }
+                else if( (i_id & 0xF8FF) == 0x88BD )
+                {
+                    i_fourcc = VLC_FOURCC('d','t','s','b');
+                    i_cat = AUDIO_ES;
+#ifdef AUTO_SPAWN
+                    if( !p_input->stream.b_seekable )
+                    if( config_GetInt( p_input, "audio-channel" )
+                            == ((i_id & 0x700) >> 8) ||
+                        ( config_GetInt( p_input, "audio-channel" ) < 0
+                          && !((i_id & 0x700) >> 8)) )
+                    switch( config_GetInt( p_input, "audio-type" ) )
+                    {
+                    case -1:
+                    case REQUESTED_DTS:
+                        b_auto_spawn = VLC_TRUE;
                     }
-                    else if( (i_id & 0xF0FF) == 0xA0BD )
+#endif
+                }
+                else if( (i_id & 0xF0FF) == 0x80BD )
+                {
+                    /* A52 audio (0x80->0x8F) */
+                    i_fourcc = VLC_FOURCC('a','5','2','b');
+                    i_cat = AUDIO_ES;
+#ifdef AUTO_SPAWN
+                    if( !p_input->stream.b_seekable )
+                    if( config_GetInt( p_input, "audio-channel" )
+                            == ((i_id & 0xF00) >> 8) ||
+                        ( config_GetInt( p_input, "audio-channel" ) < 0
+                          && !((i_id & 0xF00) >> 8)) )
+                    switch( config_GetInt( p_input, "audio-type" ) )
                     {
-                        /* LPCM audio (0xA0->0xAF) */
-                        p_es->i_fourcc = VLC_FOURCC('l','p','c','m');
-                        p_es->i_cat = AUDIO_ES;
+                    case -1:
+                    case REQUESTED_A52:
+                        b_auto_spawn = VLC_TRUE;
                     }
-                    else
+#endif
+                }
+                else if( (i_id & 0xE0FF) == 0x20BD )
+                {
+                    /* Subtitles video (0x20->0x3F) */
+                    i_fourcc = VLC_FOURCC('s','p','u','b');
+                    i_cat = SPU_ES;
+#ifdef AUTO_SPAWN
+                    if( !p_input->stream.b_seekable )
+                    if( config_GetInt( p_input, "spu-channel" )
+                           == ((i_id & 0x1F00) >> 8) )
                     {
-                        p_es->i_fourcc = 0;
+                        b_auto_spawn = VLC_TRUE;
                     }
+#endif
+                }
+                else if( (i_id & 0xF0FF) == 0xA0BD )
+                {
+                    /* LPCM audio (0xA0->0xAF) */
+                    i_fourcc = VLC_FOURCC('l','p','c','b');
+                    i_cat = AUDIO_ES;
                 }
+                else
+                {
+                    i_cat = UNKNOWN_ES;
+                    i_fourcc = 0;
+                }
+
+                p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
+                                    i_id, i_cat, NULL, 0 );
+
+                p_es->i_stream_id = p_data->p_demux_start[3];
+                p_es->i_fourcc = i_fourcc;
+
+                if( b_auto_spawn ) input_SelectES( p_input, p_es );
 
                 /* Tell the interface the stream has changed */
                 p_input->stream.b_changed = 1;
@@ -933,13 +974,13 @@ static es_descriptor_t * ParsePS( input_thread_t * p_input,
  *****************************************************************************/
 static void DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
 {
-    u32                 i_code;
-    vlc_bool_t          b_trash = 0;
-    es_descriptor_t *   p_es = NULL;
+    uint32_t i_code;
+    vlc_bool_t b_trash = 0;
+    es_descriptor_t * p_es = NULL;
 
-    i_code = ((u32)p_data->p_demux_start[0] << 24)
-                | ((u32)p_data->p_demux_start[1] << 16)
-                | ((u32)p_data->p_demux_start[2] << 8)
+    i_code = ((uint32_t)p_data->p_demux_start[0] << 24)
+                | ((uint32_t)p_data->p_demux_start[1] << 16)
+                | ((uint32_t)p_data->p_demux_start[2] << 8)
                 | p_data->p_demux_start[3];
     if( i_code <= 0x1BC )
     {
@@ -948,8 +989,8 @@ static void DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
         case 0x1BA: /* PACK_START_CODE */
             {
                 /* Read the SCR. */
-                mtime_t         scr_time;
-                u32             i_mux_rate;
+                mtime_t scr_time;
+                uint32_t i_mux_rate;
 
                 if( (p_data->p_demux_start[4] & 0xC0) == 0x40 )
                 {
@@ -974,7 +1015,7 @@ static void DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
                                         >> 11);
 
                     /* mux_rate */
-                    i_mux_rate = ((u32)U16_AT(p_header + 10) << 6)
+                    i_mux_rate = ((uint32_t)U16_AT(p_header + 10) << 6)
                                    | (p_header[12] >> 2);
                     /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
                      * This is the biggest kludge ever !
@@ -1031,11 +1072,11 @@ static void DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
             DecodePSM( p_input, p_data );
             b_trash = 1;
             break;
-    
+
         case 0x1B9: /* PROGRAM_END_CODE */
             b_trash = 1;
             break;
-   
+
         default:
             /* This should not happen */
             b_trash = 1;
@@ -1070,7 +1111,7 @@ static void DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
     }
 }
 
+
 /*
  * TS Demultiplexing
  */
@@ -1138,8 +1179,8 @@ static ssize_t ReadTS( input_thread_t * p_input, data_packet_t ** pp_data )
 static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
                      psi_callback_t pf_psi_callback )
 {
-    u16                 i_pid;
-    int                 i_dummy;
+    uint16_t            i_pid;
+    unsigned int        i_dummy;
     vlc_bool_t          b_adaptation;         /* Adaptation field is present */
     vlc_bool_t          b_payload;                 /* Packet carries payload */
     vlc_bool_t          b_unit_start;  /* A PSI or a PES start in the packet */
@@ -1150,6 +1191,8 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
     es_descriptor_t *   p_es = NULL;
     es_ts_data_t *      p_es_demux = NULL;
     pgrm_ts_data_t *    p_pgrm_demux = NULL;
+    stream_ts_data_t *  p_stream_demux =
+                          (stream_ts_data_t *)p_input->stream.p_demux_data;
 
 #define p (p_data->p_demux_start)
     /* Extract flags values from TS common header. */
@@ -1158,9 +1201,15 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
     b_adaptation = (p[3] & 0x20);
     b_payload = (p[3] & 0x10);
 
+    /* Was there a transport error ? */
+    if ( p[1] & 0x80 )
+    {
+        msg_Warn( p_input, "transport_error_indicator set for PID %d counter %x", i_pid, p[3] & 0x0f );
+    }
+
     /* Find out the elementary stream. */
     vlc_mutex_lock( &p_input->stream.stream_lock );
-    
+
     for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number; i_dummy ++ )
     {
         if( (( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
@@ -1170,20 +1219,20 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
             break;
         }
     }
-            
-    p_es= input_FindES( p_input, i_pid );
-    
+
+    p_es = input_FindES( p_input, i_pid );
+
     if( (p_es != NULL) && (p_es->p_demux_data != NULL) )
     {
         p_es_demux = (es_ts_data_t *)p_es->p_demux_data;
-        
+
         if( p_es_demux->b_psi )
         {
             b_psi = 1;
         }
         else
         {
-            p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data; 
+            p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
         }
     }
 
@@ -1196,17 +1245,17 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
     }
     else if( p_es->p_decoder_fifo == NULL && !b_psi )
     {
-        b_trash = 1; 
+        b_trash = 1;
     }
 
     vlc_mutex_unlock( &p_input->stream.control.control_lock );
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
 
-    /* Don't change the order of the tests : if b_psi then p_pgrm_demux 
+    /* Don't change the order of the tests : if b_psi then p_pgrm_demux
      * may still be null. Who said it was ugly ?
      * I have written worse. --Meuuh */
-    if( ( p_es  ) && 
+    if( ( p_es ) &&
         ((p_es->p_decoder_fifo != NULL) || b_psi || b_pcr ) )
     {
         p_es->c_packets++;
@@ -1223,7 +1272,7 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
         {
             /* p[4] is adaptation_field_length minus one */
             p_data->p_payload_start += 5 + p[4];
-    
+
             /* The adaptation field can be limited to the
              * adaptation_field_length byte, so that there is nothing to do:
              * skip this possibility */
@@ -1235,12 +1284,19 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
                  * 183 bytes. */
                 if( b_payload ? (p[4] > 182) : (p[4] != 183) )
                 {
-                    msg_Warn( p_input, "invalid TS adaptation field (%p)",
-                              p_data );
+                    msg_Warn( p_input, "invalid TS adaptation field for PID %d (%2x)",
+                              i_pid, p[4] );
                     p_data->b_discard_payload = 1;
                     p_es->c_invalid_packets++;
+
+                    /* The length was invalid so we shouldn't have added it to
+                     * p_payload_start above.  Ensure p_payload_start has a
+                     * valid value by setting it equal to p_payload_end.  This
+                     * also stops any data being processed from the packet.
+                     */
+                    p_data->p_payload_start = p_data->p_payload_end;
                 }
-    
+
                 /* Now we are sure that the byte containing flags is present:
                  * read it */
                 else
@@ -1250,26 +1306,29 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
                     {
                         msg_Warn( p_input,
                             "discontinuity_indicator encountered by TS demux "
-                            "(position read: %d, saved: %d)",
-                            p[5] & 0x80, p_es_demux->i_continuity_counter );
-    
+                            "(PID %d: current %d, packet %d)",
+                            i_pid,
+                            ( p_es_demux->i_continuity_counter ) & 0x0f,
+                            p[3] & 0x0f );
+
                         /* If the PID carries the PCR, there will be a system
                          * time-based discontinuity. We let the PCR decoder
                          * handle that. */
                         p_es->p_pgrm->i_synchro_state = SYNCHRO_REINIT;
-    
-                        /* There also may be a continuity_counter
-                         * discontinuity: resynchronize our counter with
-                         * the one of the stream. */
-                        p_es_demux->i_continuity_counter = (p[3] & 0x0f) - 1;
+
+                        /* Don't resynchronise the counter here - it will
+                         * be checked later and b_lost will then be set if
+                         * necessary.
+                         */
                     }
-    
+
                 } /* valid TS adaptation field ? */
             } /* length > 0 */
         } /* has adaptation field */
         /* Check the continuity of the stream. */
         i_dummy = ((p[3] & 0x0f) - p_es_demux->i_continuity_counter) & 0x0f;
-        if( i_dummy == 1 )
+        if( b_payload &&
+                ( i_dummy == 1 || (b_psi && p_stream_demux->b_buggy_psi ) ) )
         {
             /* Everything is ok, just increase our counter */
             (p_es_demux->i_continuity_counter)++;
@@ -1284,11 +1343,19 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
                  * the packet. */
                 b_trash = 1;
             }
+            else if( !b_payload )
+            {
+                /* If there is no payload, the counter should be unchanged */
+                msg_Warn( p_input, "packet rxd for PID %d with no payload but "
+                        "wrong counter: current %d, packet %d", i_pid,
+                        p_es_demux->i_continuity_counter & 0x0f, p[3] & 0x0f );
+            }
             else if( i_dummy <= 0 )
             {
                 /* Duplicate packet: mark it as being to be trashed. */
                 msg_Warn( p_input,
-                          "duplicate packet received by TS demux" );
+                          "duplicate packet received for PID %d (counter %d)",
+                          p_es->i_id, p[3] & 0x0f );
                 b_trash = 1;
             }
             else if( p_es_demux->i_continuity_counter == 0xFF )
@@ -1308,7 +1375,8 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
                  * as we don't know, do as if we missed a packet to be sure
                  * to recover from this situation */
                 msg_Warn( p_input,
-                          "packet lost by TS demux: current %d, packet %d",
+                          "packet lost by TS demux for PID %d: current %d, packet %d",
+                          i_pid,
                           p_es_demux->i_continuity_counter & 0x0f,
                           p[3] & 0x0f );
                 b_lost = 1;
@@ -1316,7 +1384,7 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
             } /* not continuous */
         } /* continuity */
     } /* if selected or PCR */
-    
+
     /* Handle PCR */
     if( b_pcr && b_adaptation && (p[5] & 0x10) && p[4]>=7 )
     {
@@ -1328,7 +1396,7 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
                    ( (mtime_t)p[9] << 1 ) |
                    ( (mtime_t)p[10] >> 7 );
         /* Call the pace control. */
-        for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number; 
+        for( i_dummy = 0; i_dummy < p_input->stream.i_pgrm_number;
                                 i_dummy ++ )
         {
             if( ( ( pgrm_ts_data_t * ) p_input->stream.pp_programs[i_dummy]->
@@ -1340,7 +1408,7 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
         }
 
     }
-    
+
     /* Trash the packet if it has no payload or if it isn't selected */
     if( b_trash )
     {
@@ -1357,7 +1425,7 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
         else
         {
             /* The payload carries a PES stream */
-            GatherPES( p_input, p_data, p_es, b_unit_start, b_lost ); 
+            GatherPES( p_input, p_data, p_es, b_unit_start, b_lost );
         }
 
     }
@@ -1365,4 +1433,3 @@ static void DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
 #undef p
 
 }
-