]> git.sesse.net Git - vlc/blob - modules/demux/mpeg/ps.c
* all : demuxers *have to* set pf_demux_control. (demux_vaControlDefault
[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.10 2003/09/07 22:48:29 fenrir 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     p_input->pf_demux_control = demux_vaControlDefault;
78
79     /* Initialize access plug-in structures. */
80     if( p_input->i_mtu == 0 )
81     {
82         /* Improve speed. */
83         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
84     }
85
86     /* Have a peep at the show. */
87     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
88     {
89         /* Stream shorter than 4 bytes... */
90         msg_Err( p_input, "cannot peek()" );
91         return -1;
92     }
93
94     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
95     {
96         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
97         {
98             /* User forced */
99             msg_Warn( p_input, "this does not look like an MPEG PS stream, continuing" );
100         }
101         else
102         {
103             msg_Warn( p_input, "this does not look like an MPEG PS stream, "
104                                "but continuing anyway" );
105         }
106     }
107     else if( *(p_peek + 3) <= 0xb9 )
108     {
109         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) )
110         {
111             /* User forced */
112             msg_Err( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
113         }
114         else
115         {
116             msg_Warn( p_input, "this seems to be an elementary stream (ES module?), but continuing" );
117         }
118     }
119
120     p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
121     if( p_demux == NULL )
122     {
123         return -1;
124     }
125
126     p_input->p_private = (void*)&p_demux->mpeg;
127     p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
128     if( p_demux->p_module == NULL )
129     {
130         free( p_input->p_demux_data );
131         return -1;
132     }
133
134     if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
135     {
136         module_Unneed( p_input, p_demux->p_module );
137         free( p_input->p_demux_data );
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     
145     if( p_input->stream.b_seekable )
146     {
147         stream_ps_data_t * p_demux_data =
148              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
149
150         /* Pre-parse the stream to gather stream_descriptor_t. */
151         p_input->stream.pp_programs[0]->b_is_ok = 0;
152         p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
153
154         while( !p_input->b_die && !p_input->b_error
155                 && !p_demux_data->b_has_PSM )
156         {
157             ssize_t             i_result;
158             data_packet_t *     p_data;
159
160             i_result = p_demux->mpeg.pf_read_ps( p_input, &p_data );
161
162             if( i_result == 0 )
163             {
164                 /* EOF */
165                 vlc_mutex_lock( &p_input->stream.stream_lock );
166                 p_input->stream.pp_programs[0]->b_is_ok = 1;
167                 vlc_mutex_unlock( &p_input->stream.stream_lock );
168                 break;
169             }
170             else if( i_result == -1 )
171             {
172                 p_input->b_error = 1;
173                 break;
174             }
175
176             p_demux->mpeg.pf_parse_ps( p_input, p_data );
177             input_DeletePacket( p_input->p_method_data, p_data );
178
179             /* File too big. */
180             if( p_input->stream.p_selected_area->i_tell >
181                                                     INPUT_PREPARSE_LENGTH )
182             {
183                 break;
184             }
185         }
186         input_AccessReinit( p_input );
187         p_input->pf_seek( p_input, (off_t)0 );
188         vlc_mutex_lock( &p_input->stream.stream_lock );
189
190         if( p_demux_data->b_has_PSM )
191         {
192             /* (The PSM decoder will care about spawning the decoders) */
193             p_input->stream.pp_programs[0]->b_is_ok = 1;
194         }
195 #ifdef AUTO_SPAWN
196         else
197         {
198             /* (We have to do it ourselves) */
199             unsigned int i_es;
200
201             /* FIXME: we should do multiple passes in case an audio type
202              * is not present */
203             for( i_es = 0;
204                  i_es < p_input->stream.pp_programs[0]->i_es_number;
205                  i_es++ )
206             {
207 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
208                 switch( p_es->i_fourcc )
209                 {
210                     case VLC_FOURCC('m','p','g','v'):
211                         input_SelectES( p_input, p_es );
212                         break;
213
214                     case VLC_FOURCC('m','p','g','a'):
215                         if( config_GetInt( p_input, "audio-channel" )
216                                 == (p_es->i_id & 0x1F) ||
217                            ( config_GetInt( p_input, "audio-channel" ) < 0
218                               && !(p_es->i_id & 0x1F) ) )
219                         switch( config_GetInt( p_input, "audio-type" ) )
220                         {
221                         case -1:
222                         case REQUESTED_MPEG:
223                             input_SelectES( p_input, p_es );
224                         }
225                         break;
226
227                     case VLC_FOURCC('d','t','s',' '):
228                     case VLC_FOURCC('d','t','s','b'):
229                         if( config_GetInt( p_input, "audio-channel" )
230                                 == ((p_es->i_id & 0x700) >> 8) ||
231                            ( config_GetInt( p_input, "audio-channel" ) < 0
232                               && !((p_es->i_id & 0x700) >> 8) ) )
233                         switch( config_GetInt( p_input, "audio-type" ) )
234                         {
235                         case -1:
236                         case REQUESTED_DTS:
237                             input_SelectES( p_input, p_es );
238                         }
239                         break;
240
241                     case VLC_FOURCC('a','5','2',' '):
242                     case VLC_FOURCC('a','5','2','b'):
243                         if( config_GetInt( p_input, "audio-channel" )
244                                 == ((p_es->i_id & 0xF00) >> 8) ||
245                            ( config_GetInt( p_input, "audio-channel" ) < 0
246                               && !((p_es->i_id & 0xF00) >> 8) ) )
247                         switch( config_GetInt( p_input, "audio-type" ) )
248                         {
249                         case -1:
250                         case REQUESTED_A52:
251                             input_SelectES( p_input, p_es );
252                         }
253                         break;
254
255                     case VLC_FOURCC('s','p','u',' '):
256                     case VLC_FOURCC('s','p','u','b'):
257                         if( config_GetInt( p_input, "spu-channel" )
258                                 == ((p_es->i_id & 0x1F00) >> 8) )
259                         {
260                             input_SelectES( p_input, p_es );
261                         }
262                         break;
263
264                     case VLC_FOURCC('l','p','c','m'):
265                     case VLC_FOURCC('l','p','c','b'):
266                         if( config_GetInt( p_input, "audio-channel" )
267                                 == ((p_es->i_id & 0x1F00) >> 8) ||
268                            ( config_GetInt( p_input, "audio-channel" ) < 0
269                               && !((p_es->i_id & 0x1F00) >> 8) ) )
270                         switch( config_GetInt( p_input, "audio-type" ) )
271                         {
272                         case -1:
273                         case REQUESTED_LPCM:
274                             input_SelectES( p_input, p_es );
275                         }
276                         break;
277                 }
278 #undef p_es
279             }
280         }
281 #endif
282         input_DumpStream( p_input );
283         vlc_mutex_unlock( &p_input->stream.stream_lock );
284     }
285     else
286     {
287         /* The programs will be added when we read them. */
288         vlc_mutex_lock( &p_input->stream.stream_lock );
289         p_input->stream.pp_programs[0]->b_is_ok = 0;
290         vlc_mutex_unlock( &p_input->stream.stream_lock );
291     }
292
293     return 0;
294 }
295
296 /*****************************************************************************
297  * Deactivate: deinitialize PS structures
298  *****************************************************************************/
299 static void Deactivate( vlc_object_t * p_this )
300 {
301     input_thread_t *    p_input = (input_thread_t *)p_this;
302
303     module_Unneed( p_input, p_input->p_demux_data->p_module );
304     free( p_input->p_demux_data );
305 }
306
307 /*****************************************************************************
308  * Demux: reads and demuxes data packets
309  *****************************************************************************
310  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
311  * packets.
312  *****************************************************************************/
313 static int Demux( input_thread_t * p_input )
314 {
315     int i;
316
317     for( i = 0; i < PS_READ_ONCE; i++ )
318     {
319         data_packet_t *     p_data;
320         ssize_t             i_result;
321         i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
322
323         if( i_result <= 0 )
324         {
325             return i_result;
326         }
327
328         p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
329     }
330
331     return i;
332 }
333