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