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 $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
28 #include <string.h> /* strdup() */
31 #include <videolan/vlc.h>
33 #include <sys/types.h>
35 #include "stream_control.h"
36 #include "input_ext-intf.h"
37 #include "input_ext-dec.h"
38 #include "input_ext-plugins.h"
40 /*****************************************************************************
42 *****************************************************************************/
43 #define PS_READ_ONCE 50
45 /*****************************************************************************
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 * );
53 /*****************************************************************************
54 * Build configuration tree.
55 *****************************************************************************/
60 SET_DESCRIPTION( "ISO 13818-1 MPEG Program Stream input" )
61 ADD_CAPABILITY( DEMUX, 100 )
66 input_getfunctions( &p_module->p_functions->demux );
69 MODULE_DEACTIVATE_START
70 MODULE_DEACTIVATE_STOP
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 )
78 #define input p_function_list->functions.demux
79 input.pf_init = PSInit;
81 input.pf_demux = PSDemux;
82 input.pf_rewind = NULL;
87 * Data reading functions
90 /*****************************************************************************
91 * PSRead: reads one PS packet
92 *****************************************************************************/
93 #define PEEK( SIZE ) \
94 i_error = input_Peek( p_input, &p_peek, SIZE ); \
99 else if( i_error < SIZE ) \
105 static __inline__ ssize_t PSRead( input_thread_t * p_input,
106 data_packet_t ** pp_data )
109 size_t i_packet_size;
110 ssize_t i_error, i_read;
112 /* Read what we believe to be a packet header. */
115 if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
117 if( *p_peek || *(p_peek + 1) || *(p_peek + 2) )
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) );
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 )
130 p_input->p_current_data++;
136 /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
137 if( p_peek[3] != 0xB9 )
139 /* The packet is at least 6 bytes long. */
142 if( p_peek[3] != 0xBA )
144 /* That's the case for all packets, except pack header. */
145 i_packet_size = (p_peek[4] << 8) | p_peek[5];
150 if( (p_peek[4] & 0xC0) == 0x40 )
155 else if( (p_peek[4] & 0xF0) == 0x20 )
162 intf_ErrMsg( "Unable to determine stream type" );
169 /* System End Code */
173 /* Fetch a packet of the appropriate size. */
174 i_read = input_SplitBuffer( p_input, pp_data, i_packet_size + 6 );
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) )
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. */
187 p_input->p_current_data += i_stuffing;
193 /*****************************************************************************
194 * PSInit: initializes PS structures
195 *****************************************************************************/
196 static int PSInit( input_thread_t * p_input )
200 /* Initialize access plug-in structures. */
201 if( p_input->i_mtu == 0 )
204 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
207 /* Have a peep at the show. */
208 if( input_Peek( p_input, &p_peek, 4 ) < 4 )
210 /* Stream shorter than 4 bytes... */
211 intf_ErrMsg( "input error: cannot peek() (mpeg_ps)" );
215 if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
217 if( p_input->psz_demux && strncmp( p_input->psz_demux, "ps", 3 ) )
220 intf_ErrMsg( "input error: this doesn't seem like an MPEG stream, continuing" );
224 intf_WarnMsg( 2, "input: PS plug-in discarded (no startcode)" );
228 else if( *(p_peek + 3) <= 0xb9 )
230 if( p_input->psz_demux && strncmp( p_input->psz_demux, "ps", 3 ) )
233 intf_ErrMsg( "input error: this seems to be an elementary stream (ES plug-in ?),");
234 intf_ErrMsg( "but continuing" );
238 intf_WarnMsg( 2, "input: PS plug-in discarded (ES startcode)" );
243 if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
247 input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
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] ;
254 if( p_input->stream.b_seekable )
256 stream_ps_data_t * p_demux_data =
257 (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
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;
263 while( !p_input->b_die && !p_input->b_error
264 && !p_demux_data->b_has_PSM )
267 data_packet_t * p_data;
269 i_result = PSRead( p_input, &p_data );
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 );
279 else if( i_result == -1 )
281 p_input->b_error = 1;
285 input_ParsePS( p_input, p_data );
286 input_DeletePacket( p_input->p_method_data, p_data );
289 if( p_input->stream.p_selected_area->i_tell >
290 INPUT_PREPARSE_LENGTH )
295 p_input->pf_seek( p_input, (off_t)0 );
296 input_AccessReinit( p_input );
297 vlc_mutex_lock( &p_input->stream.stream_lock );
299 if( p_demux_data->b_has_PSM )
301 /* (The PSM decoder will care about spawning the decoders) */
302 p_input->stream.pp_programs[0]->b_is_ok = 1;
307 /* (We have to do it ourselves) */
310 /* FIXME: we should do multiple passes in case an audio type
313 i_es < p_input->stream.pp_programs[0]->i_es_number;
316 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
317 switch( p_es->i_type )
321 input_SelectES( p_input, p_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 ) )
334 input_SelectES( p_input, p_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 ) )
347 input_SelectES( p_input, p_es );
352 if( config_GetIntVariable( INPUT_SUBTITLE_VAR )
353 == ((p_es->i_id & 0x1F00) >> 8) )
355 input_SelectES( p_input, p_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 ) )
368 input_SelectES( p_input, p_es );
376 if( p_main->b_stats )
378 input_DumpStream( p_input );
380 vlc_mutex_unlock( &p_input->stream.stream_lock );
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 );
394 /*****************************************************************************
395 * PSEnd: frees unused data
396 *****************************************************************************/
397 static void PSEnd( input_thread_t * p_input )
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
406 *****************************************************************************/
407 static int PSDemux( input_thread_t * p_input )
411 for( i = 0; i < PS_READ_ONCE; i++ )
413 data_packet_t * p_data;
416 i_result = PSRead( p_input, &p_data );
423 input_DemuxPS( p_input, p_data );