]> git.sesse.net Git - vlc/blobdiff - src/input/mpeg_system.c
Modified in order to add network input under Win32.
[vlc] / src / input / mpeg_system.c
index 94a0e0bd325356e55a086c78808fbf9eb46a2add..a630f8bb62e77946c9458020b45f79df74c9c258 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.43 2001/03/07 00:18:46 henri Exp $
+ * $Id: mpeg_system.c,v 1.54 2001/05/07 03:14:09 stef Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Michel Lespinasse <walken@via.ecp.fr>
@@ -31,6 +31,8 @@
 #include "defs.h"
 
 #include <stdlib.h>
+#include <string.h>                                    /* memcpy(), memset() */
+#include <sys/types.h>                                              /* off_t */
 
 #include "config.h"
 #include "common.h"
@@ -140,14 +142,16 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
     if( MoveChunk( p_header, &p_data, &p_byte, PES_HEADER_SIZE )
             != PES_HEADER_SIZE )
     {
-        intf_WarnMsg( 3, "PES packet too short to have a header" );
+        intf_WarnMsg( 1, "PES packet too short to have a header" );
         p_input->pf_delete_pes( p_input->p_method_data, p_pes );
         p_pes = NULL;
         return;
     }
 
     /* Get the PES size if defined */
-    p_es->i_pes_real_size = U16_AT(p_header + 4) + 6;
+    p_es->i_pes_real_size = U16_AT(p_header + 4);
+    if( p_es->i_pes_real_size )
+        p_es->i_pes_real_size += 6;
 
     /* First read the 6 header bytes common to all PES packets:
      * use them to test the PES validity */
@@ -167,7 +171,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
         {
             /* PES_packet_length is set and != total received payload */
             /* Warn the decoder that the data may be corrupt. */
-            intf_WarnMsg( 3, "PES sizes do not match : packet corrupted" );
+            intf_WarnMsg( 1, "PES sizes do not match : packet corrupted" );
         }
 
         switch( p_es->i_stream_id )
@@ -198,7 +202,7 @@ void input_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 )
                 {
-                    intf_WarnMsg( 3,
+                    intf_WarnMsg( 1,
                             "PES packet too short to have a MPEG-2 header" );
                     p_input->pf_delete_pes( p_input->p_method_data,
                                             p_pes );
@@ -215,7 +219,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                 {
                     if( i_max_len < 7 )
                     {
-                        intf_WarnMsg( 3,
+                        intf_WarnMsg( 1,
                             "PES packet too short to have a MPEG-2 header" );
                         p_input->pf_delete_pes( p_input->p_method_data,
                                                 p_pes );
@@ -233,7 +237,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                     {
                         if( i_max_len < 12 )
                         {
-                            intf_WarnMsg( 3,
+                            intf_WarnMsg( 1,
                               "PES packet too short to have a MPEG-2 header" );
                             p_input->pf_delete_pes( p_input->p_method_data,
                                                     p_pes );
@@ -264,7 +268,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                     i_pes_header_size++;
                     if( MoveChunk( NULL, &p_data, &p_byte, 1 ) != 1 )
                     {
-                        intf_WarnMsg( 3,
+                        intf_WarnMsg( 1,
                             "PES packet too short to have a MPEG-1 header" );
                         p_input->pf_delete_pes( p_input->p_method_data, p_pes );
                         p_pes = NULL;
@@ -288,7 +292,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                     i_pes_header_size += 2;
                     if( MoveChunk( NULL, &p_data, &p_byte, 2 ) != 2 )
                     {
-                        intf_WarnMsg( 3,
+                        intf_WarnMsg( 1,
                             "PES packet too short to have a MPEG-1 header" );
                         p_input->pf_delete_pes( p_input->p_method_data, p_pes );
                         p_pes = NULL;
@@ -308,7 +312,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                     i_pes_header_size += 4;
                     if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
                     {
-                        intf_WarnMsg( 3,
+                        intf_WarnMsg( 1,
                             "PES packet too short to have a MPEG-1 header" );
                         p_input->pf_delete_pes( p_input->p_method_data, p_pes );
                         p_pes = NULL;
@@ -326,7 +330,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
                         i_pes_header_size += 5;
                         if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 )
                         {
-                            intf_WarnMsg( 3,
+                            intf_WarnMsg( 1,
                               "PES packet too short to have a MPEG-1 header" );
                             p_input->pf_delete_pes( p_input->p_method_data,
                                                     p_pes );
@@ -657,6 +661,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
     es_descriptor_t *   p_es = NULL;
 
     i_code = p_data->p_payload_start[3];
+
     if( i_code > 0xBC ) /* ES start code */
     {
         u16                 i_id;
@@ -701,6 +706,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                     {
                         /* MPEG video */
                         p_es->i_type = MPEG2_VIDEO_ES;
+                        p_es->i_cat = VIDEO_ES;
 #ifdef AUTO_SPAWN
                         if( !p_input->stream.b_seekable )
                             input_SelectES( p_input, p_es );
@@ -711,6 +717,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                         /* MPEG audio */
                         p_es->i_type = MPEG2_AUDIO_ES;
                         p_es->b_audio = 1;
+                        p_es->i_cat = AUDIO_ES;
 #ifdef AUTO_SPAWN
                         if( !p_input->stream.b_seekable )
                         if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
@@ -730,6 +737,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                         /* AC3 audio (0x80->0x8F) */
                         p_es->i_type = AC3_AUDIO_ES;
                         p_es->b_audio = 1;
+                        p_es->i_cat = AUDIO_ES;
 #ifdef AUTO_SPAWN
                         if( !p_input->stream.b_seekable )
                         if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
@@ -748,6 +756,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                     {
                         /* Subtitles video (0x20->0x3F) */
                         p_es->i_type = DVD_SPU_ES;
+                        p_es->i_cat = SPU_ES;
 #ifdef AUTO_SPAWN
                         if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
                                 == ((p_es->i_id & 0x1F00) >> 8) )
@@ -762,6 +771,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input,
                         /* LPCM audio (0xA0->0xAF) */
                         p_es->i_type = LPCM_AUDIO_ES;
                         p_es->b_audio = 1;
+                        p_es->i_cat = AUDIO_ES;
                         /* FIXME : write the decoder */
                     }
                     else
@@ -806,7 +816,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
 
                     if( MoveChunk( p_header, &p_data, &p_byte, 14 ) != 14 )
                     {
-                        intf_WarnMsg( 3, "Packet too short to have a header" );
+                        intf_WarnMsg( 1, "Packet too short to have a header" );
                         b_trash = 1;
                         break;
                     }
@@ -831,7 +841,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
 
                     if( MoveChunk( p_header, &p_data, &p_byte, 12 ) != 12 )
                     {
-                        intf_WarnMsg( 3, "Packet too short to have a header" );
+                        intf_WarnMsg( 1, "Packet too short to have a header" );
                         b_trash = 1;
                         break;
                     }
@@ -876,7 +886,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( 3, "Unwanted packet received with start code 0x%.8x",
                           i_code );
         }
     }
@@ -1038,7 +1048,7 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
                     /* If this is a PCR_PID, and this TS packet contains a
                      * PCR, we pass it along to the PCR decoder. */
 
-                    if( (p_pgrm_demux->i_pcr_pid == i_pid) && (p[5] & 0x10) )
+                    if( !b_psi && (p_pgrm_demux->i_pcr_pid == i_pid) && (p[5] & 0x10) )
                     {
                         /* There should be a PCR field in the packet, check
                          * if the adaptation field is long enough to carry
@@ -1073,7 +1083,7 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
                  * draft. As there is nothing interesting in this packet
                  * (except PCR that have already been handled), we can trash
                  * the packet. */
-                intf_WarnMsg( 1,
+                intf_WarnMsg( 3,
                               "Packet without payload received by TS demux" );
                 b_trash = 1;
             }
@@ -1081,7 +1091,7 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
             {
                 /* FIXME: this can never happen, can it ? --Meuuh */
                 /* Duplicate packet: mark it as being to be trashed. */
-                intf_WarnMsg( 1, "Duplicate packet received by TS demux" );
+                intf_WarnMsg( 3, "Duplicate packet received by TS demux" );
                 b_trash = 1;
             }
             else if( p_es_demux->i_continuity_counter == 0xFF )
@@ -1162,8 +1172,8 @@ void input_DemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
          * (see ISO/IEC 13818 (2.4.4.2) which should be set to 0x00 */
         if( (u8)p[0] != 0x00 )
         {
-        /*    intf_WarnMsg( 2, */
-            intf_ErrMsg( "Non zero pointer field found. Trying to continue" );
+            intf_WarnMsg( 2, 
+                          "Non zero pointer field found. Trying to continue" );
             p+=(u8)p[0];
         }
         else
@@ -1173,7 +1183,7 @@ void input_DemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
 
         if( ((u8)(p[1]) & 0xc0) != 0x80 ) 
         {
-            intf_ErrMsg( "Invalid PSI packet" );
+            intf_WarnMsg( 2, "Invalid PSI packet" );
             p_psi->b_trash = 1;
         }
         else 
@@ -1264,7 +1274,7 @@ void input_DemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
                 input_DecodePMT( p_input, p_es );
                 break;
             default:
-                intf_ErrMsg("Received unknown PSI in demuxPSI");
+                intf_WarnMsg(2, "Received unknown PSI in demuxPSI");
         }
     }
 #undef p_psi    
@@ -1292,7 +1302,7 @@ static void input_DecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
         /* PAT has changed. We are going to delete all programms and 
          * create new ones. We chose not to only change what was needed
          * as a PAT change may mean the stream is radically changing and
-         * this is a secure method to avoid krashed */
+         * this is a secure method to avoid krashes */
         pgrm_descriptor_t * p_pgrm;
         es_descriptor_t   * p_current_es;
         es_ts_data_t      * p_es_demux;
@@ -1360,7 +1370,7 @@ static void input_DecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
  * DecodePMT : decode a given Program Stream Map
  * ***************************************************************************
  * When the PMT changes, it may mean a deep change in the stream, and it is
- * careful to deletes the ES and add them again. If the PMT doesn't change,
+ * careful to delete the ES and add them again. If the PMT doesn't change,
  * there no need to do anything.
  *****************************************************************************/
 static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
@@ -1382,15 +1392,52 @@ static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
         int                 i_section_length,i_current_section;
         int                 i_prog_info_length, i_loop;
         int                 i_es_info_length, i_pid, i_stream_type;
+        int                 i_audio_es, i_spu_es;
+        int                 i_required_audio_es, i_required_spu_es;
         
         p_current_section = p_psi->buffer;
         p_current_data = p_psi->buffer;
         
         p_pgrm_data->i_pcr_pid = U16_AT(p_current_section + 8) & 0x1fff;
         
+        i_audio_es = 0;
+        i_spu_es = 0;
+        
         /* Lock stream information */
         vlc_mutex_lock( &p_input->stream.stream_lock );
 
+        /* Get the number of the required audio stream */
+        if( p_main->b_audio )
+        {
+            /* Default is the first one */
+            i_required_audio_es = main_GetIntVariable( INPUT_CHANNEL_VAR, 1 );
+            if( i_required_audio_es < 0 )
+            {
+                main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
+                i_required_audio_es = 1;
+            }
+        }
+        else
+        {
+            i_required_audio_es = 0;
+        }
+
+        /* Same thing for subtitles */
+        if( p_main->b_video )
+        {
+            /* for spu, default is none */
+            i_required_spu_es = main_GetIntVariable( INPUT_SUBTITLE_VAR, 0 );
+            if( i_required_spu_es < 0 )
+            {
+                main_PutIntVariable( INPUT_SUBTITLE_VAR, 0 );
+                i_required_spu_es = 0;
+            }
+        }
+        else
+        {
+            i_required_spu_es = 0;
+        }
+        
         /* Delete all ES in this program  except the PSI */
         for( i_loop=0; i_loop < p_es->p_pgrm->i_es_number; i_loop++ )
         {
@@ -1422,10 +1469,46 @@ static void input_DecodePMT( 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 ) );
+
+                /* Tell the decoders what kind of stream it is */
                 p_new_es->i_type = i_stream_type;
+
+                /* Tell the interface what kind of stream it is and select 
+                 * the required ones */
+                switch( i_stream_type )
+                {
+                    case MPEG1_VIDEO_ES:
+                    case MPEG2_VIDEO_ES:
+                        p_new_es->i_cat = VIDEO_ES;
+                        input_SelectES( p_input, p_new_es );
+                        break;
+                    case MPEG1_AUDIO_ES:
+                    case MPEG2_AUDIO_ES:
+                    case LPCM_AUDIO_ES :
+                        p_new_es->i_cat = AUDIO_ES;
+                        i_audio_es += 1;
+                        if( i_audio_es == i_required_audio_es )
+                            input_SelectES( p_input, p_new_es );
+                        break;
+                    case AC3_AUDIO_ES :
+                        p_new_es->i_stream_id = 0xBD;
+                        p_new_es->i_cat = AUDIO_ES;
+                        i_audio_es += 1;
+                        if( i_audio_es == i_required_audio_es )
+                            input_SelectES( p_input, p_new_es );
+                        break;
+                    /* Not sure this one is fully norm-compliant */
+                    case DVD_SPU_ES :
+                        p_new_es->i_cat = SPU_ES;
+                        i_spu_es += 1;
+                        if( i_spu_es == i_required_spu_es )
+                            input_SelectES( p_input, p_new_es );
+                        break;
+                    default :
+                        p_new_es->i_cat = UNKNOWN_ES;
+                        break;
+                }
                 
-                /* We want to decode */
-                input_SelectES( p_input, p_new_es );
                 p_current_data += 5 + i_es_info_length;
             }
 
@@ -1436,8 +1519,16 @@ static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
             
         } while( i_current_section < p_psi->i_last_section_number );
 
+        if( i_required_audio_es > i_audio_es )
+            intf_WarnMsg( 2, "TS input: Non-existing audio es required." );
+        
+        if( i_required_spu_es > i_spu_es )
+            intf_WarnMsg( 2, "TS input: Non-existing subtitles es required." );
+        
         p_pgrm_data->i_pmt_version = p_psi->i_version_number;
 
+        /* inform interface that stream has changed */
+        p_input->stream.b_changed = 1;
     }
     
 #undef p_psi