]> git.sesse.net Git - vlc/blob - src/input/input_ps.c
The input-II. (more info by mail in about an hour)
[vlc] / src / input / input_ps.c
1 /*****************************************************************************
2  * input_ps.c: PS demux and packet management
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000 VideoLAN
5  *
6  * Authors: 
7  *
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.
12  * 
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.
17  *
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  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include "defs.h"
27
28 #include <stdlib.h>
29 #include <netinet/in.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #include "config.h"
34 #include "common.h"
35 #include "threads.h"
36 #include "mtime.h"
37
38 #include "intf_msg.h"
39
40 #include "stream_control.h"
41 #include "input_ext-intf.h"
42 #include "input_ext-dec.h"
43
44 #include "input.h"
45
46 #include "input_ps.h"
47 #include "mpeg_system.h"
48
49 #include "debug.h"
50
51 /*****************************************************************************
52  * Local prototypes
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 * );
62
63 /*
64  * Data reading functions
65  */
66
67 /*****************************************************************************
68  * PSProbe: verifies that the stream is a PS stream
69  *****************************************************************************/
70 static int PSProbe( input_thread_t * p_input )
71 {
72     /* verify that the first three bytes are 0x000001, or unscramble and
73      * re-do. */
74     return 1;
75 }
76
77 /*****************************************************************************
78  * PSInit: initializes PS structures
79  *****************************************************************************/
80 static void PSInit( input_thread_t * p_input )
81 {
82     thread_ps_data_t *  p_method;
83     stream_ps_data_t *  p_demux;
84
85     if( (p_method =
86          (thread_ps_data_t *)malloc( sizeof(thread_ps_data_t) )) == NULL )
87     {
88         intf_ErrMsg( "Out of memory" );
89         p_input->b_error = 1;
90         return;
91     }
92
93     p_input->p_method_data = (void *)p_method;
94
95     /* Re-open the socket as a buffered FILE stream */
96     if( (p_method->stream = fdopen( p_input->i_handle, "r" )) == NULL )
97     {
98         intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
99         p_input->b_error = 1;
100         return;
101     }
102     fseek( p_method->stream, 0, SEEK_SET );
103
104     /* Pre-parse the stream to gather stream_descriptor_t. */
105
106     /* FIXME */
107     p_input->stream.pp_programs =
108          (pgrm_descriptor_t **)malloc( sizeof(pgrm_descriptor_t *) );
109     p_input->stream.pp_programs[0] =
110          (pgrm_descriptor_t *)malloc( sizeof(pgrm_descriptor_t) );
111     p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_START;
112     p_input->stream.pp_programs[0]->delta_cr = 0;
113     p_input->stream.pp_programs[0]->last_cr = 0;
114     p_input->stream.pp_programs[0]->c_average_count = 0;
115
116     p_demux = (stream_ps_data_t *)malloc( sizeof( stream_ps_data_t) );
117     p_input->stream.p_demux_data = (void *)p_demux;
118     p_demux->b_is_PSM_complete = 0;
119 }
120
121 /*****************************************************************************
122  * PSEnd: frees unused data
123  *****************************************************************************/
124 static void PSEnd( input_thread_t * p_input )
125 {
126     free( p_input->stream.p_demux_data );
127     free( p_input->p_method_data );
128 }
129
130 /*****************************************************************************
131  * PSRead: reads a data packet
132  *****************************************************************************/
133 /* FIXME: read INPUT_READ_ONCE packet at once */
134 static void PSRead( input_thread_t * p_input,
135                     data_packet_t * p_packets[INPUT_READ_ONCE] )
136 {
137     byte_t              p_header[6];
138     data_packet_t *     p_data;
139     int                 i_packet_size;
140     thread_ps_data_t *  p_method;
141
142     p_method = (thread_ps_data_t *)p_input->p_method_data;
143
144     while( fread( p_header, 6, 1, p_method->stream ) != 1 )
145     {
146         int             i_error;
147         if( (i_error = ferror( p_method->stream )) )
148         {
149             intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
150             p_input->b_error = 1;
151             return;
152         }
153
154         if( feof( p_method->stream ) )
155         {
156             intf_ErrMsg( "EOF reached" );
157             p_input->b_error = 1;
158             return;
159         }
160     }
161
162     if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
163     {
164         u32         i_buffer = U32_AT(p_header);
165         intf_ErrMsg( "Garbage at input (%x)\n", i_buffer );
166         while( (i_buffer & 0xFFFFFF00) != 0x100L )
167         {
168             i_buffer <<= 8;
169             i_buffer |= getc( p_method->stream );
170             if( feof(p_method->stream) || ferror(p_method->stream) )
171             {
172                 p_input->b_error = 1;
173                 return;
174             }
175         }
176         *(u32 *)p_header = i_buffer;
177         fread( p_header + 4, 2, 1, p_method->stream );
178     }
179
180     if( U32_AT(p_header) != 0x1BA )
181     {
182         i_packet_size = U16_AT(&p_header[4]);
183     }
184     else
185     {
186         i_packet_size = 8;
187     }
188
189     if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
190     {
191         p_input->b_error = 1;
192         intf_ErrMsg( "Out of memory" );
193         return;
194     }
195
196     memcpy( p_data->p_buffer, p_header, 6 );
197
198     /* FIXME: catch EINTR ! */
199     while( fread( p_data->p_buffer + 6, i_packet_size,
200                1, p_method->stream ) != 1 )
201     {
202         int             i_error;
203         if( (i_error = ferror( p_method->stream)) )
204         {
205             intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
206             p_input->b_error = 1;
207             return;
208         }
209
210         if( feof( p_method->stream ) )
211         {
212             intf_ErrMsg( "EOF reached" );
213             p_input->b_error = 1;
214             return;
215         }
216     }
217
218     if( U32_AT(p_header) == 0x1BA )
219     {
220         /* stuffing_bytes */
221         byte_t      p_garbage[8];
222         /* FIXME: catch EINTR ! */
223         if( (p_data->p_buffer[13] & 0x3) != 0 )
224         {
225             fread( p_garbage, p_garbage[0] & 0x3, 1,
226                    p_method->stream );
227         }
228     }
229
230     memset( p_packets, 0, sizeof(p_packets) );
231     p_packets[0] = p_data;
232 }
233
234
235 /*
236  * Packet management utilities
237  */
238
239 /*****************************************************************************
240  * NewPacket: allocates a data packet
241  *****************************************************************************/
242 static struct data_packet_s * NewPacket( void * p_garbage,
243                                          size_t i_size )
244 {
245     data_packet_t * p_data;
246
247     if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
248     {
249         intf_DbgMsg( "Out of memory" );
250         return NULL;
251     }
252
253     if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
254     {
255         intf_DbgMsg( "Out of memory" );
256         free( p_data );
257         return NULL;
258     }
259
260     p_data->p_payload_start = p_data->p_buffer;
261     p_data->p_payload_end = p_data->p_buffer + i_size;
262
263     return( p_data );
264 }
265
266 /*****************************************************************************
267  * DeletePacket: deletes a data packet
268  *****************************************************************************/
269 static void DeletePacket( void * p_garbage,
270                           data_packet_t * p_data )
271 {
272     ASSERT(p_data);
273     ASSERT(p_data->p_buffer);
274     free( p_data->p_buffer );
275     free( p_data );
276 }
277
278 /*****************************************************************************
279  * DeletePES: deletes a PES packet and associated data packets
280  *****************************************************************************/
281 static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
282 {
283     data_packet_t *     p_data;
284     data_packet_t *     p_next;
285
286     p_data = p_pes->p_first;
287
288     while( p_data != NULL )
289     {
290         p_next = p_data->p_next;
291         free( p_data->p_buffer );
292         free( p_data );
293         p_data = p_next;
294     }
295
296     free( p_pes );
297 }
298
299 /*****************************************************************************
300  * PSKludge: fakes a PS plugin (FIXME)
301  *****************************************************************************/
302 input_capabilities_t * PSKludge( void )
303 {
304     input_capabilities_t *  p_plugin;
305
306     p_plugin = (input_capabilities_t *)malloc( sizeof(input_capabilities_t) );
307     p_plugin->pf_init = PSInit;
308     p_plugin->pf_read = PSRead;
309     p_plugin->pf_demux = input_DemuxPS; /* FIXME: use i_p_config_t ! */
310     p_plugin->pf_new_packet = NewPacket;
311     p_plugin->pf_delete_packet = DeletePacket;
312     p_plugin->pf_delete_pes = DeletePES;
313     p_plugin->pf_rewind = NULL;
314     p_plugin->pf_seek = NULL;
315
316     return( p_plugin );
317 }