]> git.sesse.net Git - vlc/blob - plugins/mpeg_system/mpeg_ps.c
* ALL: the first libvlc commit.
[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.15 2002/06/01 12:32:00 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_type )
203                 {
204                     case MPEG1_VIDEO_ES:
205                     case MPEG2_VIDEO_ES:
206                         input_SelectES( p_input, p_es );
207                         break;
208
209                     case MPEG1_AUDIO_ES:
210                     case MPEG2_AUDIO_ES:
211                         if( config_GetInt( p_input, "audio-channel" )
212                                 == (p_es->i_id & 0x1F) ||
213                            ( config_GetInt( p_input, "audio-channel" ) < 0
214                               && !(p_es->i_id & 0x1F) ) )
215                         switch( config_GetInt( p_input, "audio-type" ) )
216                         {
217                         case -1:
218                         case REQUESTED_MPEG:
219                             input_SelectES( p_input, p_es );
220                         }
221                         break;
222
223                     case AC3_AUDIO_ES:
224                         if( config_GetInt( p_input, "audio-channel" )
225                                 == ((p_es->i_id & 0xF00) >> 8) ||
226                            ( config_GetInt( p_input, "audio-channel" ) < 0
227                               && !((p_es->i_id & 0xF00) >> 8) ) )
228                         switch( config_GetInt( p_input, "audio-type" ) )
229                         {
230                         case -1:
231                         case REQUESTED_AC3:
232                             input_SelectES( p_input, p_es );
233                         }
234                         break;
235
236                     case DVD_SPU_ES:
237                         if( config_GetInt( p_input, "spu-channel" )
238                                 == ((p_es->i_id & 0x1F00) >> 8) )
239                         {
240                             input_SelectES( p_input, p_es );
241                         }
242                         break;
243
244                     case LPCM_AUDIO_ES:
245                         if( config_GetInt( p_input, "audio-channel" )
246                                 == ((p_es->i_id & 0x1F00) >> 8) ||
247                            ( config_GetInt( p_input, "audio-channel" ) < 0
248                               && !((p_es->i_id & 0x1F00) >> 8) ) )
249                         switch( config_GetInt( p_input, "audio-type" ) )
250                         {
251                         case -1:
252                         case REQUESTED_LPCM:
253                             input_SelectES( p_input, p_es );
254                         }
255                         break;
256                 }
257 #undef p_es
258             }
259         }
260 #endif
261         input_DumpStream( p_input );
262         vlc_mutex_unlock( &p_input->stream.stream_lock );
263     }
264     else
265     {
266         /* The programs will be added when we read them. */
267         vlc_mutex_lock( &p_input->stream.stream_lock );
268         p_input->stream.pp_programs[0]->b_is_ok = 0;
269         vlc_mutex_unlock( &p_input->stream.stream_lock );
270     }
271
272     return( 0 );
273 }
274
275 /*****************************************************************************
276  * PSEnd: frees unused data
277  *****************************************************************************/
278 static void PSEnd( input_thread_t * p_input )
279 {
280 }
281
282 /*****************************************************************************
283  * PSDemux: reads and demuxes data packets
284  *****************************************************************************
285  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
286  * packets.
287  *****************************************************************************/
288 static int PSDemux( input_thread_t * p_input )
289 {
290     int                 i;
291
292     for( i = 0; i < PS_READ_ONCE; i++ )
293     {
294         data_packet_t *     p_data;
295         ssize_t             i_result;
296         i_result = input_ReadPS( p_input, &p_data );
297
298         if( i_result <= 0 )
299         {
300             return( i_result );
301         }
302
303         input_DemuxPS( p_input, p_data );
304     }
305
306     return( i );
307 }
308