24908f9f74409fcb46b4d0c1a2c82133a3a4b48c
[vlc.git] / 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.2 2002/08/07 00:29:36 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 #include "system.h"
37
38 /*****************************************************************************
39  * Constants
40  *****************************************************************************/
41 #define PS_READ_ONCE 50
42
43 /*****************************************************************************
44  * Private structure
45  *****************************************************************************/
46 struct demux_sys_t
47 {
48     module_t *   p_module;
49     mpeg_demux_t mpeg;
50 };
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55 static int  Activate   ( vlc_object_t * );
56 static void Deactivate ( vlc_object_t * );
57 static int  Demux      ( input_thread_t * );
58
59 /*****************************************************************************
60  * Module descriptor
61  *****************************************************************************/
62 vlc_module_begin();
63     set_description( _("ISO 13818-1 MPEG Program Stream input") );
64     set_capability( "demux", 100 );
65     set_callbacks( Activate, Deactivate );
66     add_shortcut( "ps" );
67 vlc_module_end();
68
69 /*****************************************************************************
70  * Activate: initialize PS structures
71  *****************************************************************************/
72 static int Activate( vlc_object_t * p_this )
73 {
74     input_thread_t *    p_input = (input_thread_t *)p_this;
75     demux_sys_t *       p_demux;
76     byte_t *            p_peek;
77
78     /* Set the demux function */
79     p_input->pf_demux = Demux;
80
81     /* Initialize access plug-in structures. */
82     if( p_input->i_mtu == 0 )
83     {
84         /* Improve speed. */
85         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
86     }
87
88     /* Have a peep at the show. */
89     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
90     {
91         /* Stream shorter than 4 bytes... */
92         msg_Err( p_input, "cannot peek()" );
93         return -1;
94     }
95
96     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
97     {
98         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
99         {
100             /* User forced */
101             msg_Err( p_input, "this does not look like an MPEG PS stream, continuing" );
102         }
103         else
104         {
105             msg_Warn( p_input, "this does not look like an MPEG PS stream, "
106                                "but continuing anyway" );
107         }
108     }
109     else if( *(p_peek + 3) <= 0xb9 )
110     {
111         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
112         {
113             /* User forced */
114             msg_Err( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
115         }
116         else
117         {
118             msg_Warn( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
119         }
120     }
121
122     p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
123     if( p_demux == NULL )
124     {
125         return -1;
126     }
127
128     p_input->p_private = (void*)&p_demux->mpeg;
129     p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
130     if( p_demux->p_module == NULL )
131     {
132         free( p_input->p_demux_data );
133         return -1;
134     }
135
136     if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
137     {
138         module_Unneed( p_input, p_demux->p_module );
139         free( p_input->p_demux_data );
140         return -1;
141     }
142     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
143     
144     p_input->stream.p_selected_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 = p_demux->mpeg.pf_read_ps( 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             p_demux->mpeg.pf_parse_ps( 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         input_AccessReinit( p_input );
189         p_input->pf_seek( p_input, (off_t)0 );
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_fourcc )
211                 {
212                     case VLC_FOURCC('m','p','g','v'):
213                         input_SelectES( p_input, p_es );
214                         break;
215
216                     case VLC_FOURCC('m','p','g','a'):
217                         if( config_GetInt( p_input, "audio-channel" )
218                                 == (p_es->i_id & 0x1F) ||
219                            ( config_GetInt( p_input, "audio-channel" ) < 0
220                               && !(p_es->i_id & 0x1F) ) )
221                         switch( config_GetInt( p_input, "audio-type" ) )
222                         {
223                         case -1:
224                         case REQUESTED_MPEG:
225                             input_SelectES( p_input, p_es );
226                         }
227                         break;
228
229                     case VLC_FOURCC('a','5','2',' '):
230                         if( config_GetInt( p_input, "audio-channel" )
231                                 == ((p_es->i_id & 0xF00) >> 8) ||
232                            ( config_GetInt( p_input, "audio-channel" ) < 0
233                               && !((p_es->i_id & 0xF00) >> 8) ) )
234                         switch( config_GetInt( p_input, "audio-type" ) )
235                         {
236                         case -1:
237                         case REQUESTED_A52:
238                             input_SelectES( p_input, p_es );
239                         }
240                         break;
241
242                     case VLC_FOURCC('s','p','u',' '):
243                         if( config_GetInt( p_input, "spu-channel" )
244                                 == ((p_es->i_id & 0x1F00) >> 8) )
245                         {
246                             input_SelectES( p_input, p_es );
247                         }
248                         break;
249
250                     case VLC_FOURCC('l','p','c','m'):
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