1 /*****************************************************************************
2 * input_ps.c: PS demux and packet management
3 *****************************************************************************
4 * Copyright (C) 1998, 1999, 2000 VideoLAN
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
29 #include <netinet/in.h>
40 #include "stream_control.h"
41 #include "input_ext-intf.h"
42 #include "input_ext-dec.h"
47 #include "mpeg_system.h"
51 /*****************************************************************************
53 *****************************************************************************/
54 static int PSProbe ( struct input_thread_s * );
55 static void PSRead ( struct input_thread_s *,
56 data_packet_t * p_packets[INPUT_READ_ONCE] );
57 static void PSInit ( struct input_thread_s * );
58 static void PSEnd ( struct input_thread_s * );
59 static struct data_packet_s * NewPacket ( void *, size_t );
60 static void DeletePacket( void *, struct data_packet_s * );
61 static void DeletePES ( void *, struct pes_packet_s * );
64 * Data reading functions
67 /*****************************************************************************
68 * PSProbe: verifies that the stream is a PS stream
69 *****************************************************************************/
70 static int PSProbe( input_thread_t * p_input )
72 /* verify that the first three bytes are 0x000001, or unscramble and
77 /*****************************************************************************
78 * PSInit: initializes PS structures
79 *****************************************************************************/
80 static void PSInit( input_thread_t * p_input )
82 thread_ps_data_t * p_method;
85 (thread_ps_data_t *)malloc( sizeof(thread_ps_data_t) )) == NULL )
87 intf_ErrMsg( "Out of memory" );
92 p_input->p_method_data = (void *)p_method;
94 /* Re-open the socket as a buffered FILE stream */
95 if( (p_method->stream = fdopen( p_input->i_handle, "r" )) == NULL )
97 intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
101 fseek( p_method->stream, 0, SEEK_SET );
103 /* Pre-parse the stream to gather stream_descriptor_t. */
105 input_InitStream( p_input, 0 );
106 input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
109 /*****************************************************************************
110 * PSEnd: frees unused data
111 *****************************************************************************/
112 static void PSEnd( input_thread_t * p_input )
114 free( p_input->stream.p_demux_data );
115 free( p_input->p_method_data );
118 /*****************************************************************************
119 * PSRead: reads a data packet
120 *****************************************************************************/
121 /* FIXME: read INPUT_READ_ONCE packet at once */
122 static void PSRead( input_thread_t * p_input,
123 data_packet_t * p_packets[INPUT_READ_ONCE] )
126 data_packet_t * p_data;
128 thread_ps_data_t * p_method;
130 p_method = (thread_ps_data_t *)p_input->p_method_data;
132 while( fread( p_header, 6, 1, p_method->stream ) != 1 )
135 if( (i_error = ferror( p_method->stream )) )
137 intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
138 p_input->b_error = 1;
142 if( feof( p_method->stream ) )
144 intf_ErrMsg( "EOF reached" );
145 p_input->b_error = 1;
150 if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
152 u32 i_buffer = U32_AT(p_header);
153 intf_WarnMsg( 1, "Garbage at input (%x)\n", i_buffer );
154 while( (i_buffer & 0xFFFFFF00) != 0x100L )
157 i_buffer |= getc( p_method->stream );
158 if( feof(p_method->stream) || ferror(p_method->stream) )
160 p_input->b_error = 1;
164 *(u32 *)p_header = U32_AT(&i_buffer);
165 fread( p_header + 4, 2, 1, p_method->stream );
168 if( U32_AT(p_header) != 0x1BA )
170 i_packet_size = U16_AT(&p_header[4]);
174 if( (p_header[4] & 0xC0) == 0x40 )
179 else if( (p_header[4] & 0xF0) == 0x20 )
186 intf_ErrMsg( "Unable to determine stream type" );
187 p_input->b_error = 1;
192 if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
194 p_input->b_error = 1;
195 intf_ErrMsg( "Out of memory" );
199 memcpy( p_data->p_buffer, p_header, 6 );
201 /* FIXME: catch EINTR ! */
202 while( fread( p_data->p_buffer + 6, i_packet_size,
203 1, p_method->stream ) != 1 )
206 if( (i_error = ferror( p_method->stream)) )
208 intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
209 p_input->b_error = 1;
213 if( feof( p_method->stream ) )
215 intf_ErrMsg( "EOF reached" );
216 p_input->b_error = 1;
221 if( U32_AT(p_header) == 0x1BA )
223 if( i_packet_size == 8 )
225 /* MPEG-2 stuffing bytes */
227 if( (p_data->p_buffer[13] & 0x7) != 0 )
229 /* FIXME: catch EINTR ! */
230 fread( p_garbage, p_garbage[0] & 0x7, 1,
236 memset( p_packets, 0, sizeof(p_packets) );
237 p_packets[0] = p_data;
242 * Packet management utilities
245 /*****************************************************************************
246 * NewPacket: allocates a data packet
247 *****************************************************************************/
248 static struct data_packet_s * NewPacket( void * p_garbage,
251 data_packet_t * p_data;
253 if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
255 intf_DbgMsg( "Out of memory" );
259 if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
261 intf_DbgMsg( "Out of memory" );
266 p_data->p_payload_start = p_data->p_buffer;
267 p_data->p_payload_end = p_data->p_buffer + i_size;
272 /*****************************************************************************
273 * NewPES: allocates a pes packet
274 *****************************************************************************/
275 static pes_packet_t * NewPES( void * p_garbage )
277 pes_packet_t * p_pes;
279 if( (p_pes = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL )
281 intf_DbgMsg( "Out of memory" );
285 p_pes->b_messed_up = p_pes->b_data_alignment = p_pes->b_discontinuity =
286 p_pes->b_has_pts = 0;
287 p_pes->i_pes_size = 0;
288 p_pes->p_first = NULL;
293 /*****************************************************************************
294 * DeletePacket: deletes a data packet
295 *****************************************************************************/
296 static void DeletePacket( void * p_garbage,
297 data_packet_t * p_data )
300 ASSERT(p_data->p_buffer);
301 free( p_data->p_buffer );
305 /*****************************************************************************
306 * DeletePES: deletes a PES packet and associated data packets
307 *****************************************************************************/
308 static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
310 data_packet_t * p_data;
311 data_packet_t * p_next;
313 p_data = p_pes->p_first;
315 while( p_data != NULL )
317 p_next = p_data->p_next;
318 free( p_data->p_buffer );
326 /*****************************************************************************
327 * PSKludge: fakes a PS plugin (FIXME)
328 *****************************************************************************/
329 input_capabilities_t * PSKludge( void )
331 input_capabilities_t * p_plugin;
333 p_plugin = (input_capabilities_t *)malloc( sizeof(input_capabilities_t) );
334 p_plugin->pf_init = PSInit;
335 p_plugin->pf_read = PSRead;
336 p_plugin->pf_demux = input_DemuxPS; /* FIXME: use i_p_config_t ! */
337 p_plugin->pf_new_packet = NewPacket;
338 p_plugin->pf_new_pes = NewPES;
339 p_plugin->pf_delete_packet = DeletePacket;
340 p_plugin->pf_delete_pes = DeletePES;
341 p_plugin->pf_rewind = NULL;
342 p_plugin->pf_seek = NULL;