]> git.sesse.net Git - vlc/blobdiff - plugins/mpeg_system/mpeg_ps.c
* ./extras/MacOSX_dvdioctl: removed outdated files.
[vlc] / plugins / mpeg_system / mpeg_ps.c
index a043865b9afe55b6438c704585fecd4e121754d9..b9567719ae654deeebf00ceb00b27611ef0bb136 100644 (file)
@@ -2,7 +2,7 @@
  * mpeg_ps.c : Program Stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2000-2001 VideoLAN
- * $Id: mpeg_ps.c,v 1.2 2001/12/30 07:09:55 sam Exp $
+ * $Id: mpeg_ps.c,v 1.8 2002/03/18 19:14:52 sam Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
  *****************************************************************************/
 #include <stdlib.h>                                      /* malloc(), free() */
 #include <string.h>                                              /* strdup() */
+#include <errno.h>
 
 #include <videolan/vlc.h>
 
+#include <sys/types.h>
+
+#include "stream_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
+#include "input_ext-plugins.h"
+
+/*****************************************************************************
+ * Constants
+ *****************************************************************************/
+#define PS_READ_ONCE 50
+
 /*****************************************************************************
- * Capabilities defined in the other files.
+ * Local prototypes
  *****************************************************************************/
-void _M( input_getfunctions )( function_list_t * p_function_list );
+static void input_getfunctions( function_list_t * p_function_list );
+static int  PSDemux         ( struct input_thread_s * );
+static int  PSInit          ( struct input_thread_s * );
+static void PSEnd           ( struct input_thread_s * );
 
 /*****************************************************************************
  * Build configuration tree.
@@ -42,14 +58,264 @@ MODULE_CONFIG_STOP
 
 MODULE_INIT_START
     SET_DESCRIPTION( "ISO 13818-1 MPEG Program Stream input" )
-    ADD_CAPABILITY( INPUT, 100 )
+    ADD_CAPABILITY( DEMUX, 100 )
     ADD_SHORTCUT( "ps" )
 MODULE_INIT_STOP
 
 MODULE_ACTIVATE_START
-    _M( input_getfunctions )( &p_module->p_functions->input );
+    input_getfunctions( &p_module->p_functions->demux );
 MODULE_ACTIVATE_STOP
 
 MODULE_DEACTIVATE_START
 MODULE_DEACTIVATE_STOP
 
+/*****************************************************************************
+ * Functions exported as capabilities. They are declared as static so that
+ * we don't pollute the namespace too much.
+ *****************************************************************************/
+static void input_getfunctions( function_list_t * p_function_list )
+{
+#define input p_function_list->functions.demux
+    input.pf_init             = PSInit;
+    input.pf_end              = PSEnd;
+    input.pf_demux            = PSDemux;
+    input.pf_rewind           = NULL;
+#undef input
+}
+
+/*****************************************************************************
+ * PSInit: initializes PS structures
+ *****************************************************************************/
+static int PSInit( input_thread_t * p_input )
+{
+    byte_t *            p_peek;
+
+    /* Initialize access plug-in structures. */
+    if( p_input->i_mtu == 0 )
+    {
+        /* Improve speed. */
+        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
+    }
+
+    /* Have a peep at the show. */
+    if( input_Peek( p_input, &p_peek, 4 ) < 4 )
+    {
+        /* Stream shorter than 4 bytes... */
+        intf_ErrMsg( "input error: cannot peek() (mpeg_ps)" );
+        return( -1 );
+    }
+
+    if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
+    {
+        if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
+        {
+            /* User forced */
+            intf_ErrMsg( "input error: this doesn't look like an MPEG PS stream, continuing" );
+        }
+        else
+        {
+            intf_WarnMsg( 2, "input: PS plug-in discarded (no startcode)" );
+            return( -1 );
+        }
+    }
+    else if( *(p_peek + 3) <= 0xb9 )
+    {
+        if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
+        {
+            /* User forced */
+            intf_ErrMsg( "input error: this seems to be an elementary stream (ES plug-in ?),");
+            intf_ErrMsg( "but continuing" );
+        }
+        else
+        {
+            intf_WarnMsg( 2, "input: PS plug-in discarded (ES startcode)" );
+            return( -1 );
+        }
+    }
+
+    if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
+    {
+        return( -1 );
+    }
+    input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
+    
+    p_input->stream.p_selected_program = 
+            p_input->stream.pp_programs[0] ;
+    p_input->stream.p_new_program = 
+            p_input->stream.pp_programs[0] ;
+    
+    if( p_input->stream.b_seekable )
+    {
+        stream_ps_data_t * p_demux_data =
+             (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
+
+        /* Pre-parse the stream to gather stream_descriptor_t. */
+        p_input->stream.pp_programs[0]->b_is_ok = 0;
+        p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
+
+        while( !p_input->b_die && !p_input->b_error
+                && !p_demux_data->b_has_PSM )
+        {
+            ssize_t             i_result;
+            data_packet_t *     p_data;
+
+            i_result = input_ReadPS( p_input, &p_data );
+
+            if( i_result == 0 )
+            {
+                /* EOF */
+                vlc_mutex_lock( &p_input->stream.stream_lock );
+                p_input->stream.pp_programs[0]->b_is_ok = 1;
+                vlc_mutex_unlock( &p_input->stream.stream_lock );
+                break;
+            }
+            else if( i_result == -1 )
+            {
+                p_input->b_error = 1;
+                break;
+            }
+
+            input_ParsePS( p_input, p_data );
+            input_DeletePacket( p_input->p_method_data, p_data );
+
+            /* File too big. */
+            if( p_input->stream.p_selected_area->i_tell >
+                                                    INPUT_PREPARSE_LENGTH )
+            {
+                break;
+            }
+        }
+        p_input->pf_seek( p_input, (off_t)0 );
+        input_AccessReinit( p_input );
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+
+        if( p_demux_data->b_has_PSM )
+        {
+            /* (The PSM decoder will care about spawning the decoders) */
+            p_input->stream.pp_programs[0]->b_is_ok = 1;
+        }
+#ifdef AUTO_SPAWN
+        else
+        {
+            /* (We have to do it ourselves) */
+            int                 i_es;
+
+            /* FIXME: we should do multiple passes in case an audio type
+             * is not present */
+            for( i_es = 0;
+                 i_es < p_input->stream.pp_programs[0]->i_es_number;
+                 i_es++ )
+            {
+#define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
+                switch( p_es->i_type )
+                {
+                    case MPEG1_VIDEO_ES:
+                    case MPEG2_VIDEO_ES:
+                        input_SelectES( p_input, p_es );
+                        break;
+
+                    case MPEG1_AUDIO_ES:
+                    case MPEG2_AUDIO_ES:
+                        if( config_GetIntVariable( "input_channel" )
+                                == (p_es->i_id & 0x1F) ||
+                              ( config_GetIntVariable( "input_channel" ) < 0
+                                && !(p_es->i_id & 0x1F) ) )
+                        switch( config_GetIntVariable( "input_audio" ) )
+                        {
+                        case -1:
+                        case REQUESTED_MPEG:
+                            input_SelectES( p_input, p_es );
+                        }
+                        break;
+
+                    case AC3_AUDIO_ES:
+                        if( config_GetIntVariable( "input_channel" )
+                                == ((p_es->i_id & 0xF00) >> 8) ||
+                              ( config_GetIntVariable( "input_channel" ) < 0
+                                && !((p_es->i_id & 0xF00) >> 8) ) )
+                        switch( config_GetIntVariable( "input_audio" ) )
+                        {
+                        case -1:
+                        case REQUESTED_AC3:
+                            input_SelectES( p_input, p_es );
+                        }
+                        break;
+
+                    case DVD_SPU_ES:
+                        if( config_GetIntVariable( "input_subtitle" )
+                                == ((p_es->i_id & 0x1F00) >> 8) )
+                        {
+                            input_SelectES( p_input, p_es );
+                        }
+                        break;
+
+                    case LPCM_AUDIO_ES:
+                        if( config_GetIntVariable( "input_channel" )
+                                == ((p_es->i_id & 0x1F00) >> 8) ||
+                              ( config_GetIntVariable( "input_channel" ) < 0
+                                && !((p_es->i_id & 0x1F00) >> 8) ) )
+                        switch( config_GetIntVariable( "input_audio" ) )
+                        {
+                        case -1:
+                        case REQUESTED_LPCM:
+                            input_SelectES( p_input, p_es );
+                        }
+                        break;
+                }
+            }
+                    
+        }
+#endif
+        if( p_main->b_stats )
+        {
+            input_DumpStream( p_input );
+        }
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+    else
+    {
+        /* The programs will be added when we read them. */
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        p_input->stream.i_method = INPUT_METHOD_FILE;
+        p_input->stream.pp_programs[0]->b_is_ok = 0;
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * PSEnd: frees unused data
+ *****************************************************************************/
+static void PSEnd( input_thread_t * p_input )
+{
+}
+
+/*****************************************************************************
+ * PSDemux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
+ * packets.
+ *****************************************************************************/
+static int PSDemux( input_thread_t * p_input )
+{
+    int                 i;
+
+    for( i = 0; i < PS_READ_ONCE; i++ )
+    {
+        data_packet_t *     p_data;
+        ssize_t             i_result;
+
+        i_result = input_ReadPS( p_input, &p_data );
+
+        if( i_result <= 0 )
+        {
+            return( i_result );
+        }
+
+        input_DemuxPS( p_input, p_data );
+    }
+
+    return( i );
+}
+