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