]> git.sesse.net Git - vlc/blob - plugins/mpeg_system/mpeg_ps.c
50d7e4bed48f702a152f8aad9b0ba41ccb26309c
[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.11 2002/04/15 23:04:08 massiot 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 error: this doesn't look like an MPEG PS stream, but continuing anyway" );
118         }
119     }
120     else if( *(p_peek + 3) <= 0xb9 )
121     {
122         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
123         {
124             /* User forced */
125             intf_ErrMsg( "input error: this seems to be an elementary stream (ES plug-in ?),");
126             intf_ErrMsg( "but continuing" );
127         }
128         else
129         {
130             intf_WarnMsg( 2, "input error: this seems to be an elementary stream (ES plug-in ?),");
131             intf_WarnMsg( 2, "but continuing" );
132         }
133     }
134
135     if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
136     {
137         return( -1 );
138     }
139     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
140     
141     p_input->stream.p_selected_program = 
142             p_input->stream.pp_programs[0] ;
143     
144     if( p_input->stream.b_seekable )
145     {
146         stream_ps_data_t * p_demux_data =
147              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
148
149         /* Pre-parse the stream to gather stream_descriptor_t. */
150         p_input->stream.pp_programs[0]->b_is_ok = 0;
151         p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
152
153         while( !p_input->b_die && !p_input->b_error
154                 && !p_demux_data->b_has_PSM )
155         {
156             ssize_t             i_result;
157             data_packet_t *     p_data;
158
159             i_result = input_ReadPS( p_input, &p_data );
160
161             if( i_result == 0 )
162             {
163                 /* EOF */
164                 vlc_mutex_lock( &p_input->stream.stream_lock );
165                 p_input->stream.pp_programs[0]->b_is_ok = 1;
166                 vlc_mutex_unlock( &p_input->stream.stream_lock );
167                 break;
168             }
169             else if( i_result == -1 )
170             {
171                 p_input->b_error = 1;
172                 break;
173             }
174
175             input_ParsePS( p_input, p_data );
176             input_DeletePacket( p_input->p_method_data, p_data );
177
178             /* File too big. */
179             if( p_input->stream.p_selected_area->i_tell >
180                                                     INPUT_PREPARSE_LENGTH )
181             {
182                 break;
183             }
184         }
185         input_AccessReinit( p_input );
186         p_input->pf_seek( p_input, (off_t)0 );
187         vlc_mutex_lock( &p_input->stream.stream_lock );
188
189         if( p_demux_data->b_has_PSM )
190         {
191             /* (The PSM decoder will care about spawning the decoders) */
192             p_input->stream.pp_programs[0]->b_is_ok = 1;
193         }
194 #ifdef AUTO_SPAWN
195         else
196         {
197             /* (We have to do it ourselves) */
198             int                 i_es;
199
200             /* FIXME: we should do multiple passes in case an audio type
201              * is not present */
202             for( i_es = 0;
203                  i_es < p_input->stream.pp_programs[0]->i_es_number;
204                  i_es++ )
205             {
206 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
207                 switch( p_es->i_type )
208                 {
209                     case MPEG1_VIDEO_ES:
210                     case MPEG2_VIDEO_ES:
211                         input_SelectES( p_input, p_es );
212                         break;
213
214                     case MPEG1_AUDIO_ES:
215                     case MPEG2_AUDIO_ES:
216                         if( config_GetIntVariable( "input_channel" )
217                                 == (p_es->i_id & 0x1F) ||
218                               ( config_GetIntVariable( "input_channel" ) < 0
219                                 && !(p_es->i_id & 0x1F) ) )
220                         switch( config_GetIntVariable( "input_audio" ) )
221                         {
222                         case -1:
223                         case REQUESTED_MPEG:
224                             input_SelectES( p_input, p_es );
225                         }
226                         break;
227
228                     case AC3_AUDIO_ES:
229                         if( config_GetIntVariable( "input_channel" )
230                                 == ((p_es->i_id & 0xF00) >> 8) ||
231                               ( config_GetIntVariable( "input_channel" ) < 0
232                                 && !((p_es->i_id & 0xF00) >> 8) ) )
233                         switch( config_GetIntVariable( "input_audio" ) )
234                         {
235                         case -1:
236                         case REQUESTED_AC3:
237                             input_SelectES( p_input, p_es );
238                         }
239                         break;
240
241                     case DVD_SPU_ES:
242                         if( config_GetIntVariable( "input_subtitle" )
243                                 == ((p_es->i_id & 0x1F00) >> 8) )
244                         {
245                             input_SelectES( p_input, p_es );
246                         }
247                         break;
248
249                     case LPCM_AUDIO_ES:
250                         if( config_GetIntVariable( "input_channel" )
251                                 == ((p_es->i_id & 0x1F00) >> 8) ||
252                               ( config_GetIntVariable( "input_channel" ) < 0
253                                 && !((p_es->i_id & 0x1F00) >> 8) ) )
254                         switch( config_GetIntVariable( "input_audio" ) )
255                         {
256                         case -1:
257                         case REQUESTED_LPCM:
258                             input_SelectES( p_input, p_es );
259                         }
260                         break;
261                 }
262             }
263                     
264         }
265 #endif
266         if( p_main->b_stats )
267         {
268             input_DumpStream( p_input );
269         }
270         vlc_mutex_unlock( &p_input->stream.stream_lock );
271     }
272     else
273     {
274         /* The programs will be added when we read them. */
275         vlc_mutex_lock( &p_input->stream.stream_lock );
276         p_input->stream.i_method = INPUT_METHOD_FILE;
277         p_input->stream.pp_programs[0]->b_is_ok = 0;
278         vlc_mutex_unlock( &p_input->stream.stream_lock );
279     }
280
281     return( 0 );
282 }
283
284 /*****************************************************************************
285  * PSEnd: frees unused data
286  *****************************************************************************/
287 static void PSEnd( input_thread_t * p_input )
288 {
289 }
290
291 /*****************************************************************************
292  * PSDemux: reads and demuxes data packets
293  *****************************************************************************
294  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
295  * packets.
296  *****************************************************************************/
297 static int PSDemux( input_thread_t * p_input )
298 {
299     int                 i;
300
301     for( i = 0; i < PS_READ_ONCE; i++ )
302     {
303         data_packet_t *     p_data;
304         ssize_t             i_result;
305
306         i_result = input_ReadPS( p_input, &p_data );
307
308         if( i_result <= 0 )
309         {
310             return( i_result );
311         }
312
313         input_DemuxPS( p_input, p_data );
314     }
315
316     return( i );
317 }
318