1 /*****************************************************************************
2 * input_ps.c: PS demux and packet management
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: input_ps.c,v 1.4 2001/12/12 13:48:09 massiot Exp $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Cyril Deguet <asmax@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 #define MODULE_NAME mpeg_ps
26 #include "modules_inner.h"
28 /*****************************************************************************
30 *****************************************************************************/
38 #ifdef STRNCASECMP_IN_STRINGS_H
42 #include <sys/types.h>
47 #elif defined( _MSC_VER ) && defined( _WIN32 )
59 #include "stream_control.h"
60 #include "input_ext-intf.h"
61 #include "input_ext-dec.h"
62 #include "input_ext-plugins.h"
69 #include "modules_export.h"
71 /*****************************************************************************
72 * fseeko: fseeko replacement for BSDI.
73 *****************************************************************************/
75 int __sfseek __P(( FILE *, fpos_t, int ));
76 fpos_t __sftell __P(( FILE * ));
78 static __inline__ off_t fseeko( FILE *p_file, off_t i_offset, int i_pos )
80 return __sfseek( p_file, i_offset, i_pos );
84 /*****************************************************************************
86 *****************************************************************************/
87 static int PSProbe ( probedata_t * );
88 static int PSRead ( struct input_thread_s *,
89 data_packet_t * p_packets[INPUT_READ_ONCE] );
90 static void PSInit ( struct input_thread_s * );
91 static void PSEnd ( struct input_thread_s * );
92 static int PSSetProgram ( struct input_thread_s * , pgrm_descriptor_t * );
93 static void PSSeek ( struct input_thread_s *, off_t );
95 /*****************************************************************************
96 * Declare a buffer manager
97 *****************************************************************************/
98 #define FLAGS BUFFERS_NOFLAGS
100 DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO );
101 DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
102 DECLARE_BUFFERS_END( FLAGS, NB_LIFO );
103 DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO );
104 DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, 150 );
105 DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
106 DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 150, 150 );
109 /*****************************************************************************
110 * Functions exported as capabilities. They are declared as static so that
111 * we don't pollute the namespace too much.
112 *****************************************************************************/
113 void _M( input_getfunctions )( function_list_t * p_function_list )
115 #define input p_function_list->functions.input
116 p_function_list->pf_probe = PSProbe;
117 input.pf_init = PSInit;
118 input.pf_open = NULL;
119 input.pf_close = NULL;
120 input.pf_end = PSEnd;
121 input.pf_init_bit_stream = InitBitstream;
122 input.pf_set_area = NULL;
123 input.pf_set_program = PSSetProgram;
124 input.pf_read = PSRead;
125 input.pf_demux = input_DemuxPS;
126 input.pf_new_packet = input_NewPacket;
127 input.pf_new_pes = input_NewPES;
128 input.pf_delete_packet = input_DeletePacket;
129 input.pf_delete_pes = input_DeletePES;
130 input.pf_rewind = NULL;
131 input.pf_seek = PSSeek;
136 * Data reading functions
139 /*****************************************************************************
140 * PSProbe: verifies that the stream is a PS stream
141 *****************************************************************************/
142 static int PSProbe( probedata_t *p_data )
144 input_thread_t * p_input = (input_thread_t *)p_data;
146 char * psz_name = p_input->p_source;
149 if( TestMethod( INPUT_METHOD_VAR, "ps" ) )
154 if( ( strlen(psz_name) > 5 ) && (!strncasecmp( psz_name, "file:", 5 )
155 || !strncasecmp( psz_name, "http:", 5 )) )
157 /* If the user specified "file:" or "http:" then it's probably a
166 /*****************************************************************************
167 * PSInit: initializes PS structures
168 *****************************************************************************/
169 static void PSInit( input_thread_t * p_input )
171 if( (p_input->p_method_data = input_BuffersInit()) == NULL )
173 p_input->b_error = 1;
177 if( p_input->p_stream == NULL )
179 /* Re-open the socket as a buffered FILE stream */
180 p_input->p_stream = fdopen( p_input->i_handle, "r" );
182 if( p_input->p_stream == NULL )
184 intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
185 p_input->b_error = 1;
190 /* FIXME : detect if InitStream failed */
191 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
192 input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
194 p_input->stream.p_selected_program =
195 p_input->stream.pp_programs[0] ;
196 p_input->stream.p_new_program =
197 p_input->stream.pp_programs[0] ;
199 if( p_input->stream.b_seekable )
201 stream_ps_data_t * p_demux_data =
202 (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
204 rewind( p_input->p_stream );
206 /* Pre-parse the stream to gather stream_descriptor_t. */
207 p_input->stream.pp_programs[0]->b_is_ok = 0;
208 p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
210 while( !p_input->b_die && !p_input->b_error
211 && !p_demux_data->b_has_PSM )
214 data_packet_t * pp_packets[INPUT_READ_ONCE];
216 i_result = PSRead( p_input, pp_packets );
220 vlc_mutex_lock( &p_input->stream.stream_lock );
221 p_input->stream.pp_programs[0]->b_is_ok = 1;
222 vlc_mutex_unlock( &p_input->stream.stream_lock );
227 p_input->b_error = 1;
231 for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
233 /* FIXME: use i_p_config_t */
234 input_ParsePS( p_input, pp_packets[i] );
235 p_input->pf_delete_packet( p_input->p_method_data, pp_packets[i] );
239 if( p_input->stream.p_selected_area->i_tell >
240 INPUT_PREPARSE_LENGTH )
245 rewind( p_input->p_stream );
246 vlc_mutex_lock( &p_input->stream.stream_lock );
248 p_input->stream.p_selected_area->i_tell = 0;
250 if( p_demux_data->b_has_PSM )
252 /* (The PSM decoder will care about spawning the decoders) */
253 p_input->stream.pp_programs[0]->b_is_ok = 1;
258 /* (We have to do it ourselves) */
261 /* FIXME: we should do multiple passes in case an audio type
264 i_es < p_input->stream.pp_programs[0]->i_es_number;
267 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
268 switch( p_es->i_type )
272 input_SelectES( p_input, p_es );
277 if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
278 == (p_es->i_id & 0x1F) )
279 switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
282 main_PutIntVariable( INPUT_AUDIO_VAR,
285 input_SelectES( p_input, p_es );
290 if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
291 == ((p_es->i_id & 0xF00) >> 8) )
292 switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
295 main_PutIntVariable( INPUT_AUDIO_VAR,
298 input_SelectES( p_input, p_es );
303 if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
304 == ((p_es->i_id & 0x1F00) >> 8) )
306 input_SelectES( p_input, p_es );
311 if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
312 == ((p_es->i_id & 0x1F00) >> 8) )
313 switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
316 main_PutIntVariable( INPUT_AUDIO_VAR,
319 input_SelectES( p_input, p_es );
327 if( p_main->b_stats )
329 input_DumpStream( p_input );
331 vlc_mutex_unlock( &p_input->stream.stream_lock );
335 /* The programs will be added when we read them. */
336 vlc_mutex_lock( &p_input->stream.stream_lock );
337 p_input->stream.i_method = INPUT_METHOD_FILE;
338 p_input->stream.pp_programs[0]->b_is_ok = 0;
339 vlc_mutex_unlock( &p_input->stream.stream_lock );
343 /*****************************************************************************
344 * PSEnd: frees unused data
345 *****************************************************************************/
346 static void PSEnd( input_thread_t * p_input )
348 input_BuffersEnd( p_input->p_method_data );
351 /*****************************************************************************
352 * SafeRead: reads a chunk of stream and correctly detects errors
353 *****************************************************************************/
354 static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
359 while( fread( p_buffer, i_len, 1, p_input->p_stream ) != 1 )
361 if( feof( p_input->p_stream ) )
366 if( (i_error = ferror( p_input->p_stream )) )
368 intf_ErrMsg( "Read failed (%s)", strerror(i_error) );
372 vlc_mutex_lock( &p_input->stream.stream_lock );
373 p_input->stream.p_selected_area->i_tell += i_len;
374 vlc_mutex_unlock( &p_input->stream.stream_lock );
378 /*****************************************************************************
379 * PSRead: reads data packets
380 *****************************************************************************
381 * Returns -1 in case of error, 0 if everything went well, and 1 in case of
383 *****************************************************************************/
384 static int PSRead( input_thread_t * p_input,
385 data_packet_t * pp_packets[INPUT_READ_ONCE] )
388 data_packet_t * p_data;
389 size_t i_packet_size;
390 int i_packet, i_error;
392 memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
393 for( i_packet = 0; i_packet < INPUT_READ_ONCE; i_packet++ )
395 /* Read what we believe to be a packet header. */
396 if( (i_error = SafeRead( p_input, p_header, 4 )) )
401 if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
403 /* This is not the startcode of a packet. Read the stream
404 * until we find one. */
405 u32 i_startcode = U32_AT(p_header);
410 /* It is common for MPEG-1 streams to pad with zeros
411 * (although it is forbidden by the recommendation), so
412 * don't bother everybody in this case. */
413 intf_WarnMsg( 3, "Garbage at input (%.8x)", i_startcode );
416 while( (i_startcode & 0xFFFFFF00) != 0x100L )
419 if( (i_dummy = getc( p_input->p_stream )) != EOF )
421 i_startcode |= i_dummy;
429 *(u32 *)p_header = U32_AT(&i_startcode);
432 /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
433 if( U32_AT(p_header) != 0x1B9 )
435 /* The packet is at least 6 bytes long. */
436 if( (i_error = SafeRead( p_input, p_header + 4, 2 )) )
441 if( U32_AT(p_header) != 0x1BA )
443 /* That's the case for all packets, except pack header. */
444 i_packet_size = U16_AT(&p_header[4]);
449 if( (p_header[4] & 0xC0) == 0x40 )
454 else if( (p_header[4] & 0xF0) == 0x20 )
461 intf_ErrMsg( "Unable to determine stream type" );
468 /* System End Code */
472 /* Fetch a packet of the appropriate size. */
473 p_data = p_input->pf_new_packet( p_input->p_method_data,
477 intf_ErrMsg( "Out of memory" );
481 if( U32_AT(p_header) != 0x1B9 )
483 /* Copy the header we already read. */
484 memcpy( p_data->p_buffer, p_header, 6 );
486 /* Read the remaining of the packet. */
487 if( i_packet_size && (i_error =
488 SafeRead( p_input, p_data->p_buffer + 6, i_packet_size )) )
493 /* In MPEG-2 pack headers we still have to read stuffing bytes. */
494 if( U32_AT(p_header) == 0x1BA )
496 if( i_packet_size == 8 && (p_data->p_buffer[13] & 0x7) != 0 )
498 /* MPEG-2 stuffing bytes */
500 if( (i_error = SafeRead( p_input, p_garbage,
501 p_data->p_buffer[13] & 0x7)) )
510 /* Copy the small header. */
511 memcpy( p_data->p_buffer, p_header, 4 );
514 /* Give the packet to the other input stages. */
515 pp_packets[i_packet] = p_data;
521 /*****************************************************************************
522 * PSSetProgram: Does nothing since a PS Stream is mono-program
523 *****************************************************************************/
524 static int PSSetProgram( input_thread_t * p_input,
525 pgrm_descriptor_t * p_program)
529 /*****************************************************************************
530 * PSSeek: changes the stream position indicator
531 *****************************************************************************/
532 static void PSSeek( input_thread_t * p_input, off_t i_position )
534 /* A little bourrin but should work for a while --Meuuh */
535 #if defined( WIN32 ) || defined( SYS_GNU0_2 )
536 fseek( p_input->p_stream, (long)i_position, SEEK_SET );
538 fseeko( p_input->p_stream, i_position, SEEK_SET );
541 p_input->stream.p_selected_area->i_tell = i_position;