]> git.sesse.net Git - vlc/blob - modules/demux/mpeg/ps.c
* Stringreview !!!
[vlc] / modules / demux / mpeg / ps.c
1 /*****************************************************************************
2  * ps.c : Program Stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2004, 2004 VideoLAN
5  * $Id: ps.c,v 1.17 2004/01/25 20:05:28 hartman Exp $
6  *
7  * Author: 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
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include "system.h"
33
34 /*****************************************************************************
35  * Constants
36  *****************************************************************************/
37 #define PS_READ_ONCE 50
38
39 /*****************************************************************************
40  * Private structure
41  *****************************************************************************/
42 struct demux_sys_t
43 {
44     module_t *   p_module;
45     mpeg_demux_t mpeg;
46 };
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 static int  Activate   ( vlc_object_t * );
52 static void Deactivate ( vlc_object_t * );
53 static int  Demux      ( input_thread_t * );
54
55 /*****************************************************************************
56  * Module descriptor
57  *****************************************************************************/
58 vlc_module_begin();
59     set_description( _("ISO 13818-1 MPEG Program Stream input") );
60     set_capability( "demux", 1 );
61     set_callbacks( Activate, Deactivate );
62     add_shortcut( "ps" );
63 vlc_module_end();
64
65 /*****************************************************************************
66  * Activate: initialize PS structures
67  *****************************************************************************/
68 static int Activate( vlc_object_t * p_this )
69 {
70     input_thread_t *    p_input = (input_thread_t *)p_this;
71     demux_sys_t *       p_demux;
72     byte_t *            p_peek;
73
74     /* Set the demux function */
75     p_input->pf_demux = Demux;
76     p_input->pf_demux_control = demux_vaControlDefault;
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_Warn( 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         off_t i_tell = p_input->stream.p_selected_area->i_tell;
150
151         /* Pre-parse the stream to gather stream_descriptor_t. */
152         p_input->pf_seek( p_input, (off_t) 0 );
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, i_tell );
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             unsigned 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('d','t','s',' '):
230                     case VLC_FOURCC('d','t','s','b'):
231                         if( config_GetInt( p_input, "audio-channel" )
232                                 == ((p_es->i_id & 0x700) >> 8) ||
233                            ( config_GetInt( p_input, "audio-channel" ) < 0
234                               && !((p_es->i_id & 0x700) >> 8) ) )
235                         switch( config_GetInt( p_input, "audio-type" ) )
236                         {
237                         case -1:
238                         case REQUESTED_DTS:
239                             input_SelectES( p_input, p_es );
240                         }
241                         break;
242
243                     case VLC_FOURCC('a','5','2',' '):
244                     case VLC_FOURCC('a','5','2','b'):
245                         if( config_GetInt( p_input, "audio-channel" )
246                                 == ((p_es->i_id & 0xF00) >> 8) ||
247                            ( config_GetInt( p_input, "audio-channel" ) < 0
248                               && !((p_es->i_id & 0xF00) >> 8) ) )
249                         switch( config_GetInt( p_input, "audio-type" ) )
250                         {
251                         case -1:
252                         case REQUESTED_A52:
253                             input_SelectES( p_input, p_es );
254                         }
255                         break;
256
257                     case VLC_FOURCC('s','p','u',' '):
258                     case VLC_FOURCC('s','p','u','b'):
259                         if( config_GetInt( p_input, "spu-channel" )
260                                 == ((p_es->i_id & 0x1F00) >> 8) )
261                         {
262                             input_SelectES( p_input, p_es );
263                         }
264                         break;
265
266                     case VLC_FOURCC('o','g','t',' '):
267                         if( config_GetInt( p_input, "spu-channel" )
268                             == (p_es->i_id & 0x0003) )
269                         {
270                             input_SelectES( p_input, p_es );
271                         }
272                         break;
273
274                     case VLC_FOURCC('l','p','c','m'):
275                     case VLC_FOURCC('l','p','c','b'):
276                         if( config_GetInt( p_input, "audio-channel" )
277                                 == ((p_es->i_id & 0x1F00) >> 8) ||
278                            ( config_GetInt( p_input, "audio-channel" ) < 0
279                               && !((p_es->i_id & 0x1F00) >> 8) ) )
280                         switch( config_GetInt( p_input, "audio-type" ) )
281                         {
282                         case -1:
283                         case REQUESTED_LPCM:
284                             input_SelectES( p_input, p_es );
285                         }
286                         break;
287                 }
288 #undef p_es
289             }
290         }
291 #endif
292         input_DumpStream( p_input );
293         vlc_mutex_unlock( &p_input->stream.stream_lock );
294     }
295     else
296     {
297         /* The programs will be added when we read them. */
298         vlc_mutex_lock( &p_input->stream.stream_lock );
299         p_input->stream.pp_programs[0]->b_is_ok = 0;
300         vlc_mutex_unlock( &p_input->stream.stream_lock );
301     }
302
303     return 0;
304 }
305
306 /*****************************************************************************
307  * Deactivate: deinitialize PS structures
308  *****************************************************************************/
309 static void Deactivate( vlc_object_t * p_this )
310 {
311     input_thread_t *    p_input = (input_thread_t *)p_this;
312
313     module_Unneed( p_input, p_input->p_demux_data->p_module );
314     free( p_input->p_demux_data );
315 }
316
317 /*****************************************************************************
318  * Demux: reads and demuxes data packets
319  *****************************************************************************
320  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
321  * packets.
322  *****************************************************************************/
323 static int Demux( input_thread_t * p_input )
324 {
325     int i;
326
327     for( i = 0; i < PS_READ_ONCE; i++ )
328     {
329         data_packet_t *     p_data;
330         ssize_t             i_result;
331         i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
332
333         if( i_result <= 0 )
334         {
335             return i_result;
336         }
337
338         p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
339     }
340
341     return i;
342 }
343