]> git.sesse.net Git - vlc/blobdiff - src/input/mpeg_system.c
* Bug fixes and enhancements in the Gtk+/Gnome interfaces.
[vlc] / src / input / mpeg_system.c
index de041b53ac491d817b9023d555d702b52b04d155..73b463e10cdcde2d111401b9de0990bec860d953 100644 (file)
@@ -2,7 +2,7 @@
  * mpeg_system.c: TS, PS and PES management
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: mpeg_system.c,v 1.38 2001/02/21 04:38:59 henri Exp $
+ * $Id: mpeg_system.c,v 1.45 2001/03/15 01:42:20 sam Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Michel Lespinasse <walken@via.ecp.fr>
@@ -64,6 +64,7 @@ static void input_DecodePMT( input_thread_t *, es_descriptor_t *);
  *****************************************************************************
  * Small utility function used to parse discontinuous headers safely. Copies
  * i_buf_len bytes of data to a buffer and returns the size copied.
+ * It also solves some alignment problems on non-IA-32, non-PPC processors.
  * This is a variation on the theme of input_ext-dec.h:GetChunk().
  *****************************************************************************/
 static __inline__ size_t MoveChunk( byte_t * p_dest,
@@ -223,8 +224,10 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                     }
                     p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
                     ( ((mtime_t)(p_full_header[2] & 0x0E) << 29) |
-                      (((mtime_t)U16_AT(p_full_header + 3) << 14) - (1 << 14)) |
-                      ((mtime_t)U16_AT(p_full_header + 5) >> 1) ) );
+                      ((mtime_t)(p_full_header[3]) << 22) |
+                      ((mtime_t)(p_full_header[4] & 0xFE) << 14) |
+                      ((mtime_t)p_full_header[5] << 7) |
+                      ((mtime_t)p_full_header[6] >> 1) ) );
 
                     if( b_has_dts )
                     {
@@ -256,7 +259,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                 /* Cannot fail because the previous one succeeded. */
                 MoveChunk( NULL, &p_data, &p_byte, 6 );
 
-                while( *p_byte == 0xFF && i_pes_header_size < 22 )
+                while( *p_byte == 0xFF && i_pes_header_size < 23 )
                 {
                     i_pes_header_size++;
                     if( MoveChunk( NULL, &p_data, &p_byte, 1 ) != 1 )
@@ -268,7 +271,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                         return;
                     }
                 }
-                if( i_pes_header_size == 22 )
+                if( i_pes_header_size == 23 )
                 {
                     intf_ErrMsg( "Too much MPEG-1 stuffing" );
                     p_input->pf_delete_pes( p_input->p_method_data, p_pes );
@@ -313,9 +316,10 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                     }
 
                     p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm,
-                      ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
-                        (((mtime_t)U16_AT(p_ts + 1) << 14) - (1 << 14)) |
-                        ((mtime_t)U16_AT(p_ts + 3) >> 1) ) );
+                       ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
+                         (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
+                         ((mtime_t)p_ts[3] << 7) |
+                         ((mtime_t)p_ts[4] >> 1) ) );
 
                     if( b_has_dts )
                     {
@@ -333,8 +337,9 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                         p_pes->i_dts = input_ClockGetTS( p_input,
                                                          p_es->p_pgrm,
                             ( ((mtime_t)(p_ts[0] & 0x0E) << 29) |
-                              (((mtime_t)U16_AT(p_ts + 1) << 14) - (1 << 14)) |
-                              ((mtime_t)U16_AT(p_ts + 3) >> 1) ) );
+                              (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) |
+                              ((mtime_t)p_ts[3] << 7) |
+                              ((mtime_t)p_ts[4] >> 1) ) );
                     }
                 }
             }
@@ -500,17 +505,21 @@ static u16 GetID( data_packet_t * p_data )
 {
     u16         i_id;
 
-    i_id = p_data->p_buffer[3];                                 /* stream_id */
+    i_id = p_data->p_payload_start[3];                                 /* stream_id */
     if( i_id == 0xBD )
     {
+        /* FIXME : this is not valid if the header is split in multiple
+         * packets */
         /* stream_private_id */
-        i_id |= p_data->p_buffer[ 9 + p_data->p_buffer[8] ] << 8;
+        i_id |= p_data->p_payload_start[ 9 + p_data->p_payload_start[8] ] << 8;
     }
     return( i_id );
 }
 
 /*****************************************************************************
  * DecodePSM: Decode the Program Stream Map information
+ *****************************************************************************
+ * FIXME : loads are not aligned in this function
  *****************************************************************************/
 static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
 {
@@ -528,7 +537,7 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
     }
 
     if( p_demux->b_has_PSM
-        && p_demux->i_PSM_version == (p_data->p_buffer[6] & 0x1F) )
+        && p_demux->i_PSM_version == (p_data->p_payload_start[6] & 0x1F) )
     {
         /* Already got that one. */
         return;
@@ -536,7 +545,7 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data )
 
     intf_DbgMsg( "Building PSM" );
     p_demux->b_has_PSM = 1;
-    p_demux->i_PSM_version = p_data->p_buffer[6] & 0x1F;
+    p_demux->i_PSM_version = p_data->p_payload_start[6] & 0x1F;
 
     /* Go to elementary_stream_map_length, jumping over
      * program_stream_info. */
@@ -647,8 +656,8 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
     u32                 i_code;
     es_descriptor_t *   p_es = NULL;
 
-    i_code = U32_AT( p_data->p_buffer );
-    if( i_code > 0x1BC ) /* ES start code */
+    i_code = p_data->p_payload_start[3];
+    if( i_code > 0xBC ) /* ES start code */
     {
         u16                 i_id;
         int                 i_dummy;
@@ -685,7 +694,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                                     i_id, 0 );
                 if( p_es != NULL )
                 {
-                    p_es->i_stream_id = p_data->p_buffer[3];
+                    p_es->i_stream_id = p_data->p_payload_start[3];
 
                     /* Set stream type and auto-spawn. */
                     if( (i_id & 0xF0) == 0xE0 )
@@ -739,6 +748,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                     {
                         /* Subtitles video (0x20->0x3F) */
                         p_es->i_type = DVD_SPU_ES;
+                        p_es->b_spu = 1;
 #ifdef AUTO_SPAWN
                         if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
                                 == ((p_es->i_id & 0x1F00) >> 8) )
@@ -777,7 +787,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
     boolean_t           b_trash = 0;
     es_descriptor_t *   p_es = NULL;
 
-    i_code = U32_AT( p_data->p_buffer );
+    i_code = U32_AT( p_data->p_payload_start );
     if( i_code <= 0x1BC )
     {
         switch( i_code )
@@ -788,30 +798,52 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
                 mtime_t         scr_time;
                 u32             i_mux_rate;
 
-                if( (p_data->p_buffer[4] & 0xC0) == 0x40 )
+                if( (p_data->p_payload_start[4] & 0xC0) == 0x40 )
                 {
                     /* MPEG-2 */
+                    byte_t      p_header[14];
+                    byte_t *    p_byte;
+                    p_byte = p_data->p_payload_start;
+
+                    if( MoveChunk( p_header, &p_data, &p_byte, 14 ) != 14 )
+                    {
+                        intf_WarnMsg( 3, "Packet too short to have a header" );
+                        b_trash = 1;
+                        break;
+                    }
                     scr_time =
-                         ((mtime_t)(p_data->p_buffer[4] & 0x38) << 27) |
-                         ((mtime_t)(U32_AT(p_data->p_buffer + 4) & 0x03FFF800)
+                         ((mtime_t)(p_header[4] & 0x38) << 27) |
+                         ((mtime_t)(U32_AT(p_header + 4) & 0x03FFF800)
                                         << 4) |
-                         ((mtime_t)(U32_AT(p_data->p_buffer + 6) & 0x03FFF800)
+                         ((( ((mtime_t)U16_AT(p_header + 6) << 16)
+                            | (mtime_t)U16_AT(p_header + 8) ) & 0x03FFF800)
                                         >> 11);
 
                     /* mux_rate */
-                    i_mux_rate = (U32_AT(p_data->p_buffer + 10) & 0xFFFFFC00);
+                    i_mux_rate = ((u32)U16_AT(p_header + 10) << 6)
+                                   | (p_header[12] >> 2);
                 }
                 else
                 {
                     /* MPEG-1 SCR is like PTS. */
+                    byte_t      p_header[12];
+                    byte_t *    p_byte;
+                    p_byte = p_data->p_payload_start;
+
+                    if( MoveChunk( p_header, &p_data, &p_byte, 12 ) != 12 )
+                    {
+                        intf_WarnMsg( 3, "Packet too short to have a header" );
+                        b_trash = 1;
+                        break;
+                    }
                     scr_time =
-                         ((mtime_t)(p_data->p_buffer[4] & 0x0E) << 29) |
-                         (((mtime_t)U16_AT(p_data->p_buffer + 5) << 14)
-                           - (1 << 14)) |
-                         ((mtime_t)U16_AT(p_data->p_buffer + 7) >> 1);
+                         ((mtime_t)(p_header[4] & 0x0E) << 29) |
+                         (((mtime_t)U32_AT(p_header + 4) & 0xFFFE00) << 6) |
+                         ((mtime_t)p_header[7] << 7) |
+                         ((mtime_t)p_header[8] >> 1);
 
                     /* mux_rate */
-                    i_mux_rate = (U32_AT(p_data->p_buffer + 8) & 0x8FFFFE);
+                    i_mux_rate = (U32_AT(p_header + 8) & 0x7FFFFE) >> 1;
                 }
                 /* Call the pace control. */
                 input_ClockManageRef( p_input, p_input->stream.pp_programs[0],
@@ -845,7 +877,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
         default:
             /* This should not happen */
             b_trash = 1;
-            intf_WarnMsg( 1, "Unwanted packet received with start code %x",
+            intf_WarnMsg( 1, "Unwanted packet received with start code 0x%.8x",
                           i_code );
         }
     }
@@ -903,7 +935,6 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
     pgrm_ts_data_t *    p_pgrm_demux = NULL;
 
     #define p (p_data->p_buffer)
-   
     /* Extract flags values from TS common header. */
     i_pid = U16_AT(&p[1]) & 0x1fff;
     b_unit_start = (p[1] & 0x40);
@@ -912,7 +943,6 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
 
     /* Find out the elementary stream. */
     vlc_mutex_lock( &p_input->stream.stream_lock );
-
         
     p_es= input_FindES( p_input, i_pid );
     
@@ -922,10 +952,11 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_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; 
     }
 
     vlc_mutex_lock( &p_input->stream.control.control_lock );
-
     if( ( p_es == NULL ) || (p_es->b_audio && p_input->stream.control.b_mute) )
     {
         /* Not selected. Just read the adaptation field for a PCR. */
@@ -938,17 +969,12 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
 
+    /* Don't change the order of the tests : if b_psi then p_pgrm_demux 
+     * may still be null. Who said it was ugly ? */
     if( ( p_es != NULL ) && 
         ((p_es->p_decoder_fifo != NULL) || b_psi 
                                    || (p_pgrm_demux->i_pcr_pid == i_pid) ) )
     {
-        p_es_demux = (es_ts_data_t *)p_es->p_demux_data;
-
-        if( ! p_es_demux->b_psi )
-        {
-            p_pgrm_demux = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data; 
-        }
-
 #ifdef STATS
         p_es->c_packets++;
 #endif
@@ -1257,7 +1283,6 @@ static void input_DecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
     stream_ts_data_t  * p_stream_data;
     es_ts_data_t      * p_demux_data;
 
-   
     p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
     
@@ -1363,6 +1388,9 @@ static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
         p_current_data = p_psi->buffer;
         
         p_pgrm_data->i_pcr_pid = U16_AT(p_current_section + 8) & 0x1fff;
+        
+        /* Lock stream information */
+        vlc_mutex_lock( &p_input->stream.stream_lock );
 
         /* Delete all ES in this program  except the PSI */
         for( i_loop=0; i_loop < p_es->p_pgrm->i_es_number; i_loop++ )
@@ -1399,7 +1427,6 @@ static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
                 
                 /* We want to decode */
                 input_SelectES( p_input, p_new_es );
-
                 p_current_data += 5 + i_es_info_length;
             }
 
@@ -1415,4 +1442,7 @@ static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
     }
     
 #undef p_psi
+
+    /*  Remove lock */
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
 }