]> git.sesse.net Git - vlc/blob - plugins/mpeg_system/mpeg_ps.c
* fixed another bug in PS demux : the first program added was at the
[vlc] / plugins / mpeg_system / mpeg_ps.c
1 /*****************************************************************************
2  * mpeg_ps.c : Program Stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: mpeg_ps.c,v 1.10 2002/04/10 17:47:58 jobi 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 <videolan/vlc.h>
32
33 #include <sys/types.h>
34
35 #include "stream_control.h"
36 #include "input_ext-intf.h"
37 #include "input_ext-dec.h"
38 #include "input_ext-plugins.h"
39
40 /*****************************************************************************
41  * Constants
42  *****************************************************************************/
43 #define PS_READ_ONCE 50
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 static void input_getfunctions( function_list_t * p_function_list );
49 static int  PSDemux         ( struct input_thread_s * );
50 static int  PSInit          ( struct input_thread_s * );
51 static void PSEnd           ( struct input_thread_s * );
52
53 /*****************************************************************************
54  * Build configuration tree.
55  *****************************************************************************/
56 MODULE_CONFIG_START
57 MODULE_CONFIG_STOP
58
59 MODULE_INIT_START
60     SET_DESCRIPTION( "ISO 13818-1 MPEG Program Stream input" )
61     ADD_CAPABILITY( DEMUX, 100 )
62     ADD_SHORTCUT( "ps" )
63 MODULE_INIT_STOP
64
65 MODULE_ACTIVATE_START
66     input_getfunctions( &p_module->p_functions->demux );
67 MODULE_ACTIVATE_STOP
68
69 MODULE_DEACTIVATE_START
70 MODULE_DEACTIVATE_STOP
71
72 /*****************************************************************************
73  * Functions exported as capabilities. They are declared as static so that
74  * we don't pollute the namespace too much.
75  *****************************************************************************/
76 static void input_getfunctions( function_list_t * p_function_list )
77 {
78 #define input p_function_list->functions.demux
79     input.pf_init             = PSInit;
80     input.pf_end              = PSEnd;
81     input.pf_demux            = PSDemux;
82     input.pf_rewind           = NULL;
83 #undef input
84 }
85
86 /*****************************************************************************
87  * PSInit: initializes PS structures
88  *****************************************************************************/
89 static int PSInit( input_thread_t * p_input )
90 {
91     byte_t *            p_peek;
92
93     /* Initialize access plug-in structures. */
94     if( p_input->i_mtu == 0 )
95     {
96         /* Improve speed. */
97         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
98     }
99
100     /* Have a peep at the show. */
101     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
102     {
103         /* Stream shorter than 4 bytes... */
104         intf_ErrMsg( "input error: cannot peek() (mpeg_ps)" );
105         return( -1 );
106     }
107
108     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
109     {
110         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
111         {
112             /* User forced */
113             intf_ErrMsg( "input error: this doesn't look like an MPEG PS stream, continuing" );
114         }
115         else
116         {
117             intf_WarnMsg( 2, "input: PS plug-in discarded (no startcode)" );
118             return( -1 );
119         }
120     }
121     else if( *(p_peek + 3) <= 0xb9 )
122     {
123         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
124         {
125             /* User forced */
126             intf_ErrMsg( "input error: this seems to be an elementary stream (ES plug-in ?),");
127             intf_ErrMsg( "but continuing" );
128         }
129         else
130         {
131             intf_WarnMsg( 2, "input: PS plug-in discarded (ES startcode)" );
132             return( -1 );
133         }
134     }
135
136     if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
137     {
138         return( -1 );
139     }
140     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
141     
142     p_input->stream.p_selected_program = 
143             p_input->stream.pp_programs[0] ;
144     
145     if( p_input->stream.b_seekable )
146     {
147         stream_ps_data_t * p_demux_data =
148              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
149
150         /* Pre-parse the stream to gather stream_descriptor_t. */
151         p_input->stream.pp_programs[0]->b_is_ok = 0;
152         p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
153
154         while( !p_input->b_die && !p_input->b_error
155                 && !p_demux_data->b_has_PSM )
156         {
157             ssize_t             i_result;
158             data_packet_t *     p_data;
159
160             i_result = input_ReadPS( p_input, &p_data );
161
162             if( i_result == 0 )
163             {
164                 /* EOF */
165                 vlc_mutex_lock( &p_input->stream.stream_lock );
166                 p_input->stream.pp_programs[0]->b_is_ok = 1;
167                 vlc_mutex_unlock( &p_input->stream.stream_lock );
168                 break;
169             }
170             else if( i_result == -1 )
171             {
172                 p_input->b_error = 1;
173                 break;
174             }
175
176             input_ParsePS( p_input, p_data );
177             input_DeletePacket( p_input->p_method_data, p_data );
178
179             /* File too big. */
180             if( p_input->stream.p_selected_area->i_tell >
181                                                     INPUT_PREPARSE_LENGTH )
182             {
183                 break;
184             }
185         }
186         input_AccessReinit( p_input );
187         p_input->pf_seek( p_input, (off_t)0 );
188         vlc_mutex_lock( &p_input->stream.stream_lock );
189
190         if( p_demux_data->b_has_PSM )
191         {
192             /* (The PSM decoder will care about spawning the decoders) */
193             p_input->stream.pp_programs[0]->b_is_ok = 1;
194         }
195 #ifdef AUTO_SPAWN
196         else
197         {
198             /* (We have to do it ourselves) */
199             int                 i_es;
200
201             /* FIXME: we should do multiple passes in case an audio type
202              * is not present */
203             for( i_es = 0;
204                  i_es < p_input->stream.pp_programs[0]->i_es_number;
205                  i_es++ )
206             {
207 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
208                 switch( p_es->i_type )
209                 {
210                     case MPEG1_VIDEO_ES:
211                     case MPEG2_VIDEO_ES:
212                         input_SelectES( p_input, p_es );
213                         break;
214
215                     case MPEG1_AUDIO_ES:
216                     case MPEG2_AUDIO_ES:
217                         if( config_GetIntVariable( "input_channel" )
218                                 == (p_es->i_id & 0x1F) ||
219                               ( config_GetIntVariable( "input_channel" ) < 0
220                                 && !(p_es->i_id & 0x1F) ) )
221                         switch( config_GetIntVariable( "input_audio" ) )
222                         {
223                         case -1:
224                         case REQUESTED_MPEG:
225                             input_SelectES( p_input, p_es );
226                         }
227                         break;
228
229                     case AC3_AUDIO_ES:
230                         if( config_GetIntVariable( "input_channel" )
231                                 == ((p_es->i_id & 0xF00) >> 8) ||
232                               ( config_GetIntVariable( "input_channel" ) < 0
233                                 && !((p_es->i_id & 0xF00) >> 8) ) )
234                         switch( config_GetIntVariable( "input_audio" ) )
235                         {
236                         case -1:
237                         case REQUESTED_AC3:
238                             input_SelectES( p_input, p_es );
239                         }
240                         break;
241
242                     case DVD_SPU_ES:
243                         if( config_GetIntVariable( "input_subtitle" )
244                                 == ((p_es->i_id & 0x1F00) >> 8) )
245                         {
246                             input_SelectES( p_input, p_es );
247                         }
248                         break;
249
250                     case LPCM_AUDIO_ES:
251                         if( config_GetIntVariable( "input_channel" )
252                                 == ((p_es->i_id & 0x1F00) >> 8) ||
253                               ( config_GetIntVariable( "input_channel" ) < 0
254                                 && !((p_es->i_id & 0x1F00) >> 8) ) )
255                         switch( config_GetIntVariable( "input_audio" ) )
256                         {
257                         case -1:
258                         case REQUESTED_LPCM:
259                             input_SelectES( p_input, p_es );
260                         }
261                         break;
262                 }
263             }
264                     
265         }
266 #endif
267         if( p_main->b_stats )
268         {
269             input_DumpStream( p_input );
270         }
271         vlc_mutex_unlock( &p_input->stream.stream_lock );
272     }
273     else
274     {
275         /* The programs will be added when we read them. */
276         vlc_mutex_lock( &p_input->stream.stream_lock );
277         p_input->stream.i_method = INPUT_METHOD_FILE;
278         p_input->stream.pp_programs[0]->b_is_ok = 0;
279         vlc_mutex_unlock( &p_input->stream.stream_lock );
280     }
281
282     return( 0 );
283 }
284
285 /*****************************************************************************
286  * PSEnd: frees unused data
287  *****************************************************************************/
288 static void PSEnd( input_thread_t * p_input )
289 {
290 }
291
292 /*****************************************************************************
293  * PSDemux: reads and demuxes data packets
294  *****************************************************************************
295  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
296  * packets.
297  *****************************************************************************/
298 static int PSDemux( input_thread_t * p_input )
299 {
300     int                 i;
301
302     for( i = 0; i < PS_READ_ONCE; i++ )
303     {
304         data_packet_t *     p_data;
305         ssize_t             i_result;
306
307         i_result = input_ReadPS( p_input, &p_data );
308
309         if( i_result <= 0 )
310         {
311             return( i_result );
312         }
313
314         input_DemuxPS( p_input, p_data );
315     }
316
317     return( i );
318 }
319