]> git.sesse.net Git - vlc/blob - plugins/mpeg_system/mpeg_ps.c
16526811e467b67e8f666d051544c8def3e60a19
[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.4 2002/03/01 00:33:18 massiot 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 <videolan/vlc.h>
32
33 #include <sys/types.h>
34
35 #include "stream_control.h"
36 #include "input_ext-intf.h"
37 #include "input_ext-dec.h"
38 #include "input_ext-plugins.h"
39
40 /*****************************************************************************
41  * Constants
42  *****************************************************************************/
43 #define PS_READ_ONCE 50
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 static void input_getfunctions( function_list_t * p_function_list );
49 static int  PSDemux         ( struct input_thread_s * );
50 static int  PSInit          ( struct input_thread_s * );
51 static void PSEnd           ( struct input_thread_s * );
52
53 /*****************************************************************************
54  * Build configuration tree.
55  *****************************************************************************/
56 MODULE_CONFIG_START
57 MODULE_CONFIG_STOP
58
59 MODULE_INIT_START
60     SET_DESCRIPTION( "ISO 13818-1 MPEG Program Stream input" )
61     ADD_CAPABILITY( DEMUX, 100 )
62     ADD_SHORTCUT( "ps" )
63 MODULE_INIT_STOP
64
65 MODULE_ACTIVATE_START
66     input_getfunctions( &p_module->p_functions->demux );
67 MODULE_ACTIVATE_STOP
68
69 MODULE_DEACTIVATE_START
70 MODULE_DEACTIVATE_STOP
71
72 /*****************************************************************************
73  * Functions exported as capabilities. They are declared as static so that
74  * we don't pollute the namespace too much.
75  *****************************************************************************/
76 static void input_getfunctions( function_list_t * p_function_list )
77 {
78 #define input p_function_list->functions.demux
79     input.pf_init             = PSInit;
80     input.pf_end              = PSEnd;
81     input.pf_demux            = PSDemux;
82     input.pf_rewind           = NULL;
83 #undef input
84 }
85
86 /*
87  * Data reading functions
88  */
89
90 /*****************************************************************************
91  * PSRead: reads one PS packet
92  *****************************************************************************/
93 #define PEEK( SIZE )                                                        \
94     i_error = input_Peek( p_input, &p_peek, SIZE );                         \
95     if( i_error == -1 )                                                     \
96     {                                                                       \
97         return( -1 );                                                       \
98     }                                                                       \
99     else if( i_error < SIZE )                                               \
100     {                                                                       \
101         /* EOF */                                                           \
102         return( 0 );                                                        \
103     }
104
105 static __inline__ ssize_t PSRead( input_thread_t * p_input,
106                                   data_packet_t ** pp_data )
107 {
108     byte_t *            p_peek;
109     size_t              i_packet_size;
110     ssize_t             i_error, i_read;
111
112     /* Read what we believe to be a packet header. */
113     PEEK( 4 );
114
115     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
116     {
117         if( *p_peek || *(p_peek + 1) || *(p_peek + 2) )
118         {
119             /* It is common for MPEG-1 streams to pad with zeros
120              * (although it is forbidden by the recommendation), so
121              * don't bother everybody in this case. */
122             intf_WarnMsg( 3, "input warning: garbage at input (0x%x%x%x%x)",
123                  *p_peek, *(p_peek + 1), *(p_peek + 2), *(p_peek + 3) );
124         }
125
126         /* This is not the startcode of a packet. Read the stream
127          * until we find one. */
128         while( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
129         {
130             p_input->p_current_data++;
131             PEEK( 4 );
132         }
133         /* Packet found. */
134     }
135
136     /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
137     if( p_peek[3] != 0xB9 )
138     {
139         /* The packet is at least 6 bytes long. */
140         PEEK( 6 );
141
142         if( p_peek[3] != 0xBA )
143         {
144             /* That's the case for all packets, except pack header. */
145             i_packet_size = (p_peek[4] << 8) | p_peek[5];
146         }
147         else
148         {
149             /* Pack header. */
150             if( (p_peek[4] & 0xC0) == 0x40 )
151             {
152                 /* MPEG-2 */
153                 i_packet_size = 8;
154             }
155             else if( (p_peek[4] & 0xF0) == 0x20 )
156             {
157                 /* MPEG-1 */
158                 i_packet_size = 6;
159             }
160             else
161             {
162                 intf_ErrMsg( "Unable to determine stream type" );
163                 return( -1 );
164             }
165         }
166     }
167     else
168     {
169         /* System End Code */
170         i_packet_size = -2;
171     }
172
173     /* Fetch a packet of the appropriate size. */
174     i_read = input_SplitBuffer( p_input, pp_data, i_packet_size + 6 );
175     if( i_read <= 0 )
176     {
177         return( i_read );
178     }
179
180     /* In MPEG-2 pack headers we still have to read stuffing bytes. */
181     if( ((*pp_data)->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
182     {
183         size_t i_stuffing = ((*pp_data)->p_demux_start[13] & 0x7);
184         /* Force refill of the input buffer - though we don't care
185          * about p_peek. Please note that this is unoptimized. */
186         PEEK( i_stuffing );
187         p_input->p_current_data += i_stuffing;
188     }
189
190     return( 1 );
191 }
192
193 /*****************************************************************************
194  * PSInit: initializes PS structures
195  *****************************************************************************/
196 static int PSInit( input_thread_t * p_input )
197 {
198     byte_t *            p_peek;
199
200     /* Initialize access plug-in structures. */
201     if( p_input->i_mtu == 0 )
202     {
203         /* Improve speed. */
204         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
205     }
206
207     /* Have a peep at the show. */
208     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
209     {
210         /* Stream shorter than 4 bytes... */
211         intf_ErrMsg( "input error: cannot peek() (mpeg_ps)" );
212         return( -1 );
213     }
214
215     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
216     {
217         if( p_input->psz_demux && strncmp( p_input->psz_demux, "ps", 3 ) )
218         {
219             /* User forced */
220             intf_ErrMsg( "input error: this doesn't seem like an MPEG stream, continuing" );
221         }
222         else
223         {
224             intf_WarnMsg( 2, "input: PS plug-in discarded (no startcode)" );
225             return( -1 );
226         }
227     }
228     else if( *(p_peek + 3) <= 0xb9 )
229     {
230         if( p_input->psz_demux && strncmp( p_input->psz_demux, "ps", 3 ) )
231         {
232             /* User forced */
233             intf_ErrMsg( "input error: this seems to be an elementary stream (ES plug-in ?),");
234             intf_ErrMsg( "but continuing" );
235         }
236         else
237         {
238             intf_WarnMsg( 2, "input: PS plug-in discarded (ES startcode)" );
239             return( -1 );
240         }
241     }
242
243     if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
244     {
245         return( -1 );
246     }
247     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
248     
249     p_input->stream.p_selected_program = 
250             p_input->stream.pp_programs[0] ;
251     p_input->stream.p_new_program = 
252             p_input->stream.pp_programs[0] ;
253     
254     if( p_input->stream.b_seekable )
255     {
256         stream_ps_data_t * p_demux_data =
257              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
258
259         /* Pre-parse the stream to gather stream_descriptor_t. */
260         p_input->stream.pp_programs[0]->b_is_ok = 0;
261         p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
262
263         while( !p_input->b_die && !p_input->b_error
264                 && !p_demux_data->b_has_PSM )
265         {
266             ssize_t             i_result;
267             data_packet_t *     p_data;
268
269             i_result = PSRead( p_input, &p_data );
270
271             if( i_result == 0 )
272             {
273                 /* EOF */
274                 vlc_mutex_lock( &p_input->stream.stream_lock );
275                 p_input->stream.pp_programs[0]->b_is_ok = 1;
276                 vlc_mutex_unlock( &p_input->stream.stream_lock );
277                 break;
278             }
279             else if( i_result == -1 )
280             {
281                 p_input->b_error = 1;
282                 break;
283             }
284
285             input_ParsePS( p_input, p_data );
286             input_DeletePacket( p_input->p_method_data, p_data );
287
288             /* File too big. */
289             if( p_input->stream.p_selected_area->i_tell >
290                                                     INPUT_PREPARSE_LENGTH )
291             {
292                 break;
293             }
294         }
295         p_input->pf_seek( p_input, (off_t)0 );
296         input_AccessReinit( p_input );
297         vlc_mutex_lock( &p_input->stream.stream_lock );
298
299         if( p_demux_data->b_has_PSM )
300         {
301             /* (The PSM decoder will care about spawning the decoders) */
302             p_input->stream.pp_programs[0]->b_is_ok = 1;
303         }
304 #ifdef AUTO_SPAWN
305         else
306         {
307             /* (We have to do it ourselves) */
308             int                 i_es;
309
310             /* FIXME: we should do multiple passes in case an audio type
311              * is not present */
312             for( i_es = 0;
313                  i_es < p_input->stream.pp_programs[0]->i_es_number;
314                  i_es++ )
315             {
316 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
317                 switch( p_es->i_type )
318                 {
319                     case MPEG1_VIDEO_ES:
320                     case MPEG2_VIDEO_ES:
321                         input_SelectES( p_input, p_es );
322                         break;
323
324                     case MPEG1_AUDIO_ES:
325                     case MPEG2_AUDIO_ES:
326                         if( config_GetIntVariable( INPUT_CHANNEL_VAR )
327                                 == (p_es->i_id & 0x1F) ||
328                               ( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
329                                 && !(p_es->i_id & 0x1F) ) )
330                         switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
331                         {
332                         case -1:
333                         case REQUESTED_MPEG:
334                             input_SelectES( p_input, p_es );
335                         }
336                         break;
337
338                     case AC3_AUDIO_ES:
339                         if( config_GetIntVariable( INPUT_CHANNEL_VAR )
340                                 == ((p_es->i_id & 0xF00) >> 8) ||
341                               ( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
342                                 && !((p_es->i_id & 0xF00) >> 8) ) )
343                         switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
344                         {
345                         case -1:
346                         case REQUESTED_AC3:
347                             input_SelectES( p_input, p_es );
348                         }
349                         break;
350
351                     case DVD_SPU_ES:
352                         if( config_GetIntVariable( INPUT_SUBTITLE_VAR )
353                                 == ((p_es->i_id & 0x1F00) >> 8) )
354                         {
355                             input_SelectES( p_input, p_es );
356                         }
357                         break;
358
359                     case LPCM_AUDIO_ES:
360                         if( config_GetIntVariable( INPUT_CHANNEL_VAR )
361                                 == ((p_es->i_id & 0x1F00) >> 8) ||
362                               ( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
363                                 && !((p_es->i_id & 0x1F00) >> 8) ) )
364                         switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
365                         {
366                         case -1:
367                         case REQUESTED_LPCM:
368                             input_SelectES( p_input, p_es );
369                         }
370                         break;
371                 }
372             }
373                     
374         }
375 #endif
376         if( p_main->b_stats )
377         {
378             input_DumpStream( p_input );
379         }
380         vlc_mutex_unlock( &p_input->stream.stream_lock );
381     }
382     else
383     {
384         /* The programs will be added when we read them. */
385         vlc_mutex_lock( &p_input->stream.stream_lock );
386         p_input->stream.i_method = INPUT_METHOD_FILE;
387         p_input->stream.pp_programs[0]->b_is_ok = 0;
388         vlc_mutex_unlock( &p_input->stream.stream_lock );
389     }
390
391     return( 0 );
392 }
393
394 /*****************************************************************************
395  * PSEnd: frees unused data
396  *****************************************************************************/
397 static void PSEnd( input_thread_t * p_input )
398 {
399 }
400
401 /*****************************************************************************
402  * PSDemux: reads and demuxes data packets
403  *****************************************************************************
404  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
405  * packets.
406  *****************************************************************************/
407 static int PSDemux( input_thread_t * p_input )
408 {
409     int                 i;
410
411     for( i = 0; i < PS_READ_ONCE; i++ )
412     {
413         data_packet_t *     p_data;
414         ssize_t             i_result;
415
416         i_result = PSRead( p_input, &p_data );
417
418         if( i_result <= 0 )
419         {
420             return( i_result );
421         }
422
423         input_DemuxPS( p_input, p_data );
424     }
425
426     return( i );
427 }
428