]> git.sesse.net Git - vlc/blob - modules/demux/mpeg/ps.c
* ./configure.ac.in: removed -W in favour of -Wtraditional.
[vlc] / modules / demux / mpeg / ps.c
1 /*****************************************************************************
2  * ps.c : Program Stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: ps.c,v 1.7 2002/12/06 16:34:07 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
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32
33 #include "system.h"
34
35 /*****************************************************************************
36  * Constants
37  *****************************************************************************/
38 #define PS_READ_ONCE 50
39
40 /*****************************************************************************
41  * Private structure
42  *****************************************************************************/
43 struct demux_sys_t
44 {
45     module_t *   p_module;
46     mpeg_demux_t mpeg;
47 };
48
49 /*****************************************************************************
50  * Local prototypes
51  *****************************************************************************/
52 static int  Activate   ( vlc_object_t * );
53 static void Deactivate ( vlc_object_t * );
54 static int  Demux      ( input_thread_t * );
55
56 /*****************************************************************************
57  * Module descriptor
58  *****************************************************************************/
59 vlc_module_begin();
60     set_description( _("ISO 13818-1 MPEG Program Stream input") );
61     set_capability( "demux", 1 );
62     set_callbacks( Activate, Deactivate );
63     add_shortcut( "ps" );
64 vlc_module_end();
65
66 /*****************************************************************************
67  * Activate: initialize PS structures
68  *****************************************************************************/
69 static int Activate( vlc_object_t * p_this )
70 {
71     input_thread_t *    p_input = (input_thread_t *)p_this;
72     demux_sys_t *       p_demux;
73     byte_t *            p_peek;
74
75     /* Set the demux function */
76     p_input->pf_demux = Demux;
77
78     /* Initialize access plug-in structures. */
79     if( p_input->i_mtu == 0 )
80     {
81         /* Improve speed. */
82         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
83     }
84
85     /* Have a peep at the show. */
86     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
87     {
88         /* Stream shorter than 4 bytes... */
89         msg_Err( p_input, "cannot peek()" );
90         return -1;
91     }
92
93     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
94     {
95         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
96         {
97             /* User forced */
98             msg_Err( p_input, "this does not look like an MPEG PS stream, continuing" );
99         }
100         else
101         {
102             msg_Warn( p_input, "this does not look like an MPEG PS stream, "
103                                "but continuing anyway" );
104         }
105     }
106     else if( *(p_peek + 3) <= 0xb9 )
107     {
108         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
109         {
110             /* User forced */
111             msg_Err( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
112         }
113         else
114         {
115             msg_Warn( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
116         }
117     }
118
119     p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
120     if( p_demux == NULL )
121     {
122         return -1;
123     }
124
125     p_input->p_private = (void*)&p_demux->mpeg;
126     p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
127     if( p_demux->p_module == NULL )
128     {
129         free( p_input->p_demux_data );
130         return -1;
131     }
132
133     if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
134     {
135         module_Unneed( p_input, p_demux->p_module );
136         free( p_input->p_demux_data );
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 = p_demux->mpeg.pf_read_ps( 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             p_demux->mpeg.pf_parse_ps( 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             unsigned 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_fourcc )
208                 {
209                     case VLC_FOURCC('m','p','g','v'):
210                         input_SelectES( p_input, p_es );
211                         break;
212
213                     case VLC_FOURCC('m','p','g','a'):
214                         if( config_GetInt( p_input, "audio-channel" )
215                                 == (p_es->i_id & 0x1F) ||
216                            ( config_GetInt( p_input, "audio-channel" ) < 0
217                               && !(p_es->i_id & 0x1F) ) )
218                         switch( config_GetInt( p_input, "audio-type" ) )
219                         {
220                         case -1:
221                         case REQUESTED_MPEG:
222                             input_SelectES( p_input, p_es );
223                         }
224                         break;
225
226                     case VLC_FOURCC('a','5','2',' '):
227                     case VLC_FOURCC('a','5','2','b'):
228                         if( config_GetInt( p_input, "audio-channel" )
229                                 == ((p_es->i_id & 0xF00) >> 8) ||
230                            ( config_GetInt( p_input, "audio-channel" ) < 0
231                               && !((p_es->i_id & 0xF00) >> 8) ) )
232                         switch( config_GetInt( p_input, "audio-type" ) )
233                         {
234                         case -1:
235                         case REQUESTED_A52:
236                             input_SelectES( p_input, p_es );
237                         }
238                         break;
239
240                     case VLC_FOURCC('s','p','u',' '):
241                     case VLC_FOURCC('s','p','u','b'):
242                         if( config_GetInt( p_input, "spu-channel" )
243                                 == ((p_es->i_id & 0x1F00) >> 8) )
244                         {
245                             input_SelectES( p_input, p_es );
246                         }
247                         break;
248
249                     case VLC_FOURCC('l','p','c','m'):
250                     case VLC_FOURCC('l','p','c','b'):
251                         if( config_GetInt( p_input, "audio-channel" )
252                                 == ((p_es->i_id & 0x1F00) >> 8) ||
253                            ( config_GetInt( p_input, "audio-channel" ) < 0
254                               && !((p_es->i_id & 0x1F00) >> 8) ) )
255                         switch( config_GetInt( p_input, "audio-type" ) )
256                         {
257                         case -1:
258                         case REQUESTED_LPCM:
259                             input_SelectES( p_input, p_es );
260                         }
261                         break;
262                 }
263 #undef p_es
264             }
265         }
266 #endif
267         input_DumpStream( p_input );
268         vlc_mutex_unlock( &p_input->stream.stream_lock );
269     }
270     else
271     {
272         /* The programs will be added when we read them. */
273         vlc_mutex_lock( &p_input->stream.stream_lock );
274         p_input->stream.pp_programs[0]->b_is_ok = 0;
275         vlc_mutex_unlock( &p_input->stream.stream_lock );
276     }
277
278     return 0;
279 }
280
281 /*****************************************************************************
282  * Deactivate: deinitialize PS structures
283  *****************************************************************************/
284 static void Deactivate( vlc_object_t * p_this )
285 {
286     input_thread_t *    p_input = (input_thread_t *)p_this;
287
288     module_Unneed( p_input, p_input->p_demux_data->p_module );
289     free( p_input->p_demux_data );
290 }
291
292 /*****************************************************************************
293  * Demux: 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 Demux( 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         i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
307
308         if( i_result <= 0 )
309         {
310             return i_result;
311         }
312
313         p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
314     }
315
316     return i;
317 }
318