1 /*****************************************************************************
2 * input_ps.c: PS demux and packet management
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: input_ps.c,v 1.12 2002/02/15 13:32:53 sam 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 /*****************************************************************************
27 *****************************************************************************/
33 #include <videolan/vlc.h>
35 #ifdef STRNCASECMP_IN_STRINGS_H
39 #include <sys/types.h>
44 #elif defined( _MSC_VER ) && defined( _WIN32 )
50 #include "stream_control.h"
51 #include "input_ext-intf.h"
52 #include "input_ext-dec.h"
53 #include "input_ext-plugins.h"
59 /*****************************************************************************
60 * fseeko: fseeko replacement for BSDI.
61 *****************************************************************************/
63 int __sfseek __P(( FILE *, fpos_t, int ));
64 fpos_t __sftell __P(( FILE * ));
66 static __inline__ off_t fseeko( FILE *p_file, off_t i_offset, int i_pos )
68 return __sfseek( p_file, i_offset, i_pos );
72 /*****************************************************************************
74 *****************************************************************************/
75 static int PSProbe ( struct input_thread_s * );
76 static int PSRead ( struct input_thread_s *, data_packet_t ** );
77 static void PSInit ( struct input_thread_s * );
78 static void PSEnd ( struct input_thread_s * );
79 static int PSSetProgram ( struct input_thread_s * , pgrm_descriptor_t * );
80 static void PSSeek ( struct input_thread_s *, off_t );
82 /*****************************************************************************
83 * Declare a buffer manager
84 *****************************************************************************/
85 #define FLAGS BUFFERS_NOFLAGS
87 DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO );
88 DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
89 DECLARE_BUFFERS_END( FLAGS, NB_LIFO );
90 DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO );
91 DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, 300 );
92 DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
93 DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 300 );
96 /*****************************************************************************
97 * Functions exported as capabilities. They are declared as static so that
98 * we don't pollute the namespace too much.
99 *****************************************************************************/
100 void _M( input_getfunctions )( function_list_t * p_function_list )
102 #define input p_function_list->functions.input
103 input.pf_probe = PSProbe;
104 input.pf_init = PSInit;
105 input.pf_open = NULL;
106 input.pf_close = NULL;
107 input.pf_end = PSEnd;
108 input.pf_init_bit_stream = InitBitstream;
109 input.pf_set_area = NULL;
110 input.pf_set_program = PSSetProgram;
111 input.pf_read = PSRead;
112 input.pf_demux = input_DemuxPS;
113 input.pf_new_packet = input_NewPacket;
114 input.pf_new_pes = input_NewPES;
115 input.pf_delete_packet = input_DeletePacket;
116 input.pf_delete_pes = input_DeletePES;
117 input.pf_rewind = NULL;
118 input.pf_seek = PSSeek;
123 * Data reading functions
126 /*****************************************************************************
127 * PSProbe: verifies that the stream is a PS stream
128 *****************************************************************************/
129 static int PSProbe( input_thread_t *p_input )
131 char * psz_name = p_input->p_source;
133 if( ( strlen(psz_name) > 5 ) && (!strncasecmp( psz_name, "file:", 5 )
134 || !strncasecmp( psz_name, "http:", 5 )) )
136 /* If the user specified "file:" or "http:" then it's probably a
141 /* Oh, we load it anyway */
145 /*****************************************************************************
146 * PSInit: initializes PS structures
147 *****************************************************************************/
148 static void PSInit( input_thread_t * p_input )
150 if( (p_input->p_method_data = input_BuffersInit()) == NULL )
152 p_input->b_error = 1;
156 if( p_input->p_stream == NULL )
158 /* Re-open the socket as a buffered FILE stream */
159 p_input->p_stream = fdopen( p_input->i_handle, "r" );
161 if( p_input->p_stream == NULL )
163 intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
164 input_BuffersEnd( p_input->p_method_data );
165 p_input->b_error = 1;
170 /* FIXME : detect if InitStream failed */
171 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
172 input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
174 p_input->stream.p_selected_program =
175 p_input->stream.pp_programs[0] ;
176 p_input->stream.p_new_program =
177 p_input->stream.pp_programs[0] ;
179 if( p_input->stream.b_seekable )
181 stream_ps_data_t * p_demux_data =
182 (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
184 rewind( p_input->p_stream );
186 /* Pre-parse the stream to gather stream_descriptor_t. */
187 p_input->stream.pp_programs[0]->b_is_ok = 0;
188 p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
190 while( !p_input->b_die && !p_input->b_error
191 && !p_demux_data->b_has_PSM )
194 data_packet_t * p_data;
195 data_packet_t * p_saved_data;
197 i_result = PSRead( p_input, &p_data );
198 p_saved_data = p_data;
200 while( p_data != NULL )
202 input_ParsePS( p_input, p_data );
203 p_data = p_data->p_next;
206 p_input->pf_delete_packet( p_input->p_method_data, p_saved_data );
211 vlc_mutex_lock( &p_input->stream.stream_lock );
212 p_input->stream.pp_programs[0]->b_is_ok = 1;
213 vlc_mutex_unlock( &p_input->stream.stream_lock );
216 else if( i_result == -1 )
218 p_input->b_error = 1;
223 if( p_input->stream.p_selected_area->i_tell >
224 INPUT_PREPARSE_LENGTH )
229 rewind( p_input->p_stream );
230 vlc_mutex_lock( &p_input->stream.stream_lock );
232 p_input->stream.p_selected_area->i_tell = 0;
234 if( p_demux_data->b_has_PSM )
236 /* (The PSM decoder will care about spawning the decoders) */
237 p_input->stream.pp_programs[0]->b_is_ok = 1;
242 /* (We have to do it ourselves) */
245 /* FIXME: we should do multiple passes in case an audio type
248 i_es < p_input->stream.pp_programs[0]->i_es_number;
251 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
252 switch( p_es->i_type )
256 input_SelectES( p_input, p_es );
261 if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
262 == (p_es->i_id & 0x1F) )
263 switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
266 main_PutIntVariable( INPUT_AUDIO_VAR,
269 input_SelectES( p_input, p_es );
274 if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
275 == ((p_es->i_id & 0xF00) >> 8) )
276 switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
279 main_PutIntVariable( INPUT_AUDIO_VAR,
282 input_SelectES( p_input, p_es );
287 if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
288 == ((p_es->i_id & 0x1F00) >> 8) )
290 input_SelectES( p_input, p_es );
295 if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
296 == ((p_es->i_id & 0x1F00) >> 8) )
297 switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
300 main_PutIntVariable( INPUT_AUDIO_VAR,
303 input_SelectES( p_input, p_es );
311 if( p_main->b_stats )
313 input_DumpStream( p_input );
315 vlc_mutex_unlock( &p_input->stream.stream_lock );
319 /* The programs will be added when we read them. */
320 vlc_mutex_lock( &p_input->stream.stream_lock );
321 p_input->stream.i_method = INPUT_METHOD_FILE;
322 p_input->stream.pp_programs[0]->b_is_ok = 0;
323 vlc_mutex_unlock( &p_input->stream.stream_lock );
327 /*****************************************************************************
328 * PSEnd: frees unused data
329 *****************************************************************************/
330 static void PSEnd( input_thread_t * p_input )
332 input_BuffersEnd( p_input->p_method_data );
335 /*****************************************************************************
336 * SafeRead: reads a chunk of stream and correctly detects errors
337 *****************************************************************************/
338 static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
343 while( fread( p_buffer, i_len, 1, p_input->p_stream ) != 1 )
345 if( feof( p_input->p_stream ) )
350 if( (i_error = ferror( p_input->p_stream )) )
352 intf_ErrMsg( "Read failed (%s)", strerror(i_error) );
356 vlc_mutex_lock( &p_input->stream.stream_lock );
357 p_input->stream.p_selected_area->i_tell += i_len;
358 vlc_mutex_unlock( &p_input->stream.stream_lock );
362 /*****************************************************************************
363 * PSRead: reads data packets
364 *****************************************************************************
365 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
367 *****************************************************************************/
368 static int PSRead( input_thread_t * p_input,
369 data_packet_t ** pp_data )
372 data_packet_t * p_data;
373 size_t i_packet_size;
374 int i_packet, i_error;
378 for( i_packet = 0; i_packet < PS_READ_ONCE; i_packet++ )
380 /* Read what we believe to be a packet header. */
381 if( (i_error = SafeRead( p_input, p_header, 4 )) <= 0 )
386 if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
388 /* This is not the startcode of a packet. Read the stream
389 * until we find one. */
390 u32 i_startcode = U32_AT(p_header);
395 /* It is common for MPEG-1 streams to pad with zeros
396 * (although it is forbidden by the recommendation), so
397 * don't bother everybody in this case. */
398 intf_WarnMsg( 3, "Garbage at input (%.8x)", i_startcode );
401 while( (i_startcode & 0xFFFFFF00) != 0x100L )
404 if( (i_dummy = getc( p_input->p_stream )) != EOF )
406 i_startcode |= i_dummy;
414 *(u32 *)p_header = U32_AT(&i_startcode);
417 /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
418 if( U32_AT(p_header) != 0x1B9 )
420 /* The packet is at least 6 bytes long. */
421 if( (i_error = SafeRead( p_input, p_header + 4, 2 )) <= 0 )
426 if( U32_AT(p_header) != 0x1BA )
428 /* That's the case for all packets, except pack header. */
429 i_packet_size = U16_AT(&p_header[4]);
434 if( (p_header[4] & 0xC0) == 0x40 )
439 else if( (p_header[4] & 0xF0) == 0x20 )
446 intf_ErrMsg( "Unable to determine stream type" );
453 /* System End Code */
457 /* Fetch a packet of the appropriate size. */
458 p_data = p_input->pf_new_packet( p_input->p_method_data,
462 intf_ErrMsg( "Out of memory" );
466 if( U32_AT(p_header) != 0x1B9 )
468 /* Copy the header we already read. */
469 memcpy( p_data->p_demux_start, p_header, 6 );
471 /* Read the remaining of the packet. */
472 if( i_packet_size && (i_error =
473 SafeRead( p_input, p_data->p_demux_start + 6,
474 i_packet_size )) <= 0 )
476 p_input->pf_delete_packet( p_input->p_method_data, p_data );
480 /* In MPEG-2 pack headers we still have to read stuffing bytes. */
481 if( U32_AT(p_header) == 0x1BA )
483 if( i_packet_size == 8 && (p_data->p_demux_start[13] & 0x7) != 0 )
485 /* MPEG-2 stuffing bytes */
487 if( (i_error = SafeRead( p_input, p_garbage,
488 p_data->p_demux_start[13] & 0x7)) <= 0 )
490 p_input->pf_delete_packet( p_input->p_method_data,
499 /* Copy the small header. */
500 memcpy( p_data->p_demux_start, p_header, 4 );
503 /* Give the packet to the other input stages. */
505 pp_data = &p_data->p_next;
508 return( i_packet + 1 );
511 /*****************************************************************************
512 * PSSetProgram: Does nothing since a PS Stream is mono-program
513 *****************************************************************************/
514 static int PSSetProgram( input_thread_t * p_input,
515 pgrm_descriptor_t * p_program)
519 /*****************************************************************************
520 * PSSeek: changes the stream position indicator
521 *****************************************************************************/
522 static void PSSeek( input_thread_t * p_input, off_t i_position )
524 /* A little bourrin but should work for a while --Meuuh */
525 #if defined( WIN32 ) || defined( SYS_GNU0_2 )
526 fseek( p_input->p_stream, (long)i_position, SEEK_SET );
528 fseeko( p_input->p_stream, i_position, SEEK_SET );
531 p_input->stream.p_selected_area->i_tell = i_position;