* ./modules/*: moved plugins to the new tree. Yet untested builds include
[vlc.git] / modules / demux / mpeg / ps.c
1 /*****************************************************************************
2  * mpeg_ps.c : Program Stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: ps.c,v 1.1 2002/08/04 17:23:42 sam Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>                                              /* strdup() */
29 #include <errno.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33
34 #include <sys/types.h>
35
36 /*****************************************************************************
37  * Constants
38  *****************************************************************************/
39 #define PS_READ_ONCE 50
40
41 /*****************************************************************************
42  * Local prototypes
43  *****************************************************************************/
44 static int  Activate ( vlc_object_t * );
45 static int  Demux ( input_thread_t * );
46
47 /*****************************************************************************
48  * Module descriptor
49  *****************************************************************************/
50 vlc_module_begin();
51     set_description( _("ISO 13818-1 MPEG Program Stream input") );
52     set_capability( "demux", 100 );
53     set_callbacks( Activate, NULL );
54     add_shortcut( "ps" );
55 vlc_module_end();
56
57 /*****************************************************************************
58  * Activate: initializes PS structures
59  *****************************************************************************/
60 static int Activate( vlc_object_t * p_this )
61 {
62     input_thread_t *    p_input = (input_thread_t *)p_this;
63     byte_t *            p_peek;
64
65     /* Set the demux function */
66     p_input->pf_demux = Demux;
67
68     /* Initialize access plug-in structures. */
69     if( p_input->i_mtu == 0 )
70     {
71         /* Improve speed. */
72         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
73     }
74
75     /* Have a peep at the show. */
76     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
77     {
78         /* Stream shorter than 4 bytes... */
79         msg_Err( p_input, "cannot peek()" );
80         return( -1 );
81     }
82
83     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
84     {
85         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
86         {
87             /* User forced */
88             msg_Err( p_input, "this does not look like an MPEG PS stream, continuing" );
89         }
90         else
91         {
92             msg_Warn( p_input, "this does not look like an MPEG PS stream, "
93                                "but continuing anyway" );
94         }
95     }
96     else if( *(p_peek + 3) <= 0xb9 )
97     {
98         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
99         {
100             /* User forced */
101             msg_Err( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
102         }
103         else
104         {
105             msg_Warn( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
106         }
107     }
108
109     if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
110     {
111         return( -1 );
112     }
113     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
114     
115     p_input->stream.p_selected_program = 
116             p_input->stream.pp_programs[0] ;
117     
118     if( p_input->stream.b_seekable )
119     {
120         stream_ps_data_t * p_demux_data =
121              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
122
123         /* Pre-parse the stream to gather stream_descriptor_t. */
124         p_input->stream.pp_programs[0]->b_is_ok = 0;
125         p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
126
127         while( !p_input->b_die && !p_input->b_error
128                 && !p_demux_data->b_has_PSM )
129         {
130             ssize_t             i_result;
131             data_packet_t *     p_data;
132
133             i_result = input_ReadPS( p_input, &p_data );
134
135             if( i_result == 0 )
136             {
137                 /* EOF */
138                 vlc_mutex_lock( &p_input->stream.stream_lock );
139                 p_input->stream.pp_programs[0]->b_is_ok = 1;
140                 vlc_mutex_unlock( &p_input->stream.stream_lock );
141                 break;
142             }
143             else if( i_result == -1 )
144             {
145                 p_input->b_error = 1;
146                 break;
147             }
148
149             input_ParsePS( p_input, p_data );
150             input_DeletePacket( p_input->p_method_data, p_data );
151
152             /* File too big. */
153             if( p_input->stream.p_selected_area->i_tell >
154                                                     INPUT_PREPARSE_LENGTH )
155             {
156                 break;
157             }
158         }
159         input_AccessReinit( p_input );
160         p_input->pf_seek( p_input, (off_t)0 );
161         vlc_mutex_lock( &p_input->stream.stream_lock );
162
163         if( p_demux_data->b_has_PSM )
164         {
165             /* (The PSM decoder will care about spawning the decoders) */
166             p_input->stream.pp_programs[0]->b_is_ok = 1;
167         }
168 #ifdef AUTO_SPAWN
169         else
170         {
171             /* (We have to do it ourselves) */
172             int                 i_es;
173
174             /* FIXME: we should do multiple passes in case an audio type
175              * is not present */
176             for( i_es = 0;
177                  i_es < p_input->stream.pp_programs[0]->i_es_number;
178                  i_es++ )
179             {
180 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
181                 switch( p_es->i_fourcc )
182                 {
183                     case VLC_FOURCC('m','p','g','v'):
184                         input_SelectES( p_input, p_es );
185                         break;
186
187                     case VLC_FOURCC('m','p','g','a'):
188                         if( config_GetInt( p_input, "audio-channel" )
189                                 == (p_es->i_id & 0x1F) ||
190                            ( config_GetInt( p_input, "audio-channel" ) < 0
191                               && !(p_es->i_id & 0x1F) ) )
192                         switch( config_GetInt( p_input, "audio-type" ) )
193                         {
194                         case -1:
195                         case REQUESTED_MPEG:
196                             input_SelectES( p_input, p_es );
197                         }
198                         break;
199
200                     case VLC_FOURCC('a','5','2',' '):
201                         if( config_GetInt( p_input, "audio-channel" )
202                                 == ((p_es->i_id & 0xF00) >> 8) ||
203                            ( config_GetInt( p_input, "audio-channel" ) < 0
204                               && !((p_es->i_id & 0xF00) >> 8) ) )
205                         switch( config_GetInt( p_input, "audio-type" ) )
206                         {
207                         case -1:
208                         case REQUESTED_A52:
209                             input_SelectES( p_input, p_es );
210                         }
211                         break;
212
213                     case VLC_FOURCC('s','p','u',' '):
214                         if( config_GetInt( p_input, "spu-channel" )
215                                 == ((p_es->i_id & 0x1F00) >> 8) )
216                         {
217                             input_SelectES( p_input, p_es );
218                         }
219                         break;
220
221                     case VLC_FOURCC('l','p','c','m'):
222                         if( config_GetInt( p_input, "audio-channel" )
223                                 == ((p_es->i_id & 0x1F00) >> 8) ||
224                            ( config_GetInt( p_input, "audio-channel" ) < 0
225                               && !((p_es->i_id & 0x1F00) >> 8) ) )
226                         switch( config_GetInt( p_input, "audio-type" ) )
227                         {
228                         case -1:
229                         case REQUESTED_LPCM:
230                             input_SelectES( p_input, p_es );
231                         }
232                         break;
233                 }
234 #undef p_es
235             }
236         }
237 #endif
238         input_DumpStream( p_input );
239         vlc_mutex_unlock( &p_input->stream.stream_lock );
240     }
241     else
242     {
243         /* The programs will be added when we read them. */
244         vlc_mutex_lock( &p_input->stream.stream_lock );
245         p_input->stream.pp_programs[0]->b_is_ok = 0;
246         vlc_mutex_unlock( &p_input->stream.stream_lock );
247     }
248
249     return( 0 );
250 }
251
252 /*****************************************************************************
253  * Demux: reads and demuxes data packets
254  *****************************************************************************
255  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
256  * packets.
257  *****************************************************************************/
258 static int Demux( input_thread_t * p_input )
259 {
260     int                 i;
261
262     for( i = 0; i < PS_READ_ONCE; i++ )
263     {
264         data_packet_t *     p_data;
265         ssize_t             i_result;
266         i_result = input_ReadPS( p_input, &p_data );
267
268         if( i_result <= 0 )
269         {
270             return( i_result );
271         }
272
273         input_DemuxPS( p_input, p_data );
274     }
275
276     return( i );
277 }
278