]> git.sesse.net Git - vlc/blob - src/input/input_ps.c
5647c4a83f5b7ffe9e84d75612c4dceaef0d258d
[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
84     if( (p_method =
85          (thread_ps_data_t *)malloc( sizeof(thread_ps_data_t) )) == NULL )
86     {
87         intf_ErrMsg( "Out of memory" );
88         p_input->b_error = 1;
89         return;
90     }
91
92     p_input->p_method_data = (void *)p_method;
93
94     /* Re-open the socket as a buffered FILE stream */
95     if( (p_method->stream = fdopen( p_input->i_handle, "r" )) == NULL )
96     {
97         intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
98         p_input->b_error = 1;
99         return;
100     }
101     fseek( p_method->stream, 0, SEEK_SET );
102
103     /* Pre-parse the stream to gather stream_descriptor_t. */
104
105     input_InitStream( p_input, 0 );
106     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
107 }
108
109 /*****************************************************************************
110  * PSEnd: frees unused data
111  *****************************************************************************/
112 static void PSEnd( input_thread_t * p_input )
113 {
114     free( p_input->stream.p_demux_data );
115     free( p_input->p_method_data );
116 }
117
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] )
124 {
125     byte_t              p_header[6];
126     data_packet_t *     p_data;
127     int                 i_packet_size;
128     thread_ps_data_t *  p_method;
129
130     p_method = (thread_ps_data_t *)p_input->p_method_data;
131
132     while( fread( p_header, 6, 1, p_method->stream ) != 1 )
133     {
134         int             i_error;
135         if( (i_error = ferror( p_method->stream )) )
136         {
137             intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
138             p_input->b_error = 1;
139             return;
140         }
141
142         if( feof( p_method->stream ) )
143         {
144             intf_ErrMsg( "EOF reached" );
145             p_input->b_error = 1;
146             return;
147         }
148     }
149
150     if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
151     {
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 )
155         {
156             i_buffer <<= 8;
157             i_buffer |= getc( p_method->stream );
158             if( feof(p_method->stream) || ferror(p_method->stream) )
159             {
160                 p_input->b_error = 1;
161                 return;
162             }
163         }
164         *(u32 *)p_header = U32_AT(&i_buffer);
165         fread( p_header + 4, 2, 1, p_method->stream );
166     }
167
168     if( U32_AT(p_header) != 0x1BA )
169     {
170         i_packet_size = U16_AT(&p_header[4]);
171     }
172     else
173     {
174         if( (p_header[4] & 0xC0) == 0x40 )
175         {
176             /* MPEG-2 */
177             i_packet_size = 8;
178         }
179         else if( (p_header[4] & 0xF0) == 0x20 )
180         {
181             /* MPEG-1 */
182             i_packet_size = 6;
183         }
184         else
185         {
186             intf_ErrMsg( "Unable to determine stream type" );
187             p_input->b_error = 1;
188             return;
189         }
190     }
191
192     if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
193     {
194         p_input->b_error = 1;
195         intf_ErrMsg( "Out of memory" );
196         return;
197     }
198
199     memcpy( p_data->p_buffer, p_header, 6 );
200
201     /* FIXME: catch EINTR ! */
202     while( fread( p_data->p_buffer + 6, i_packet_size,
203                1, p_method->stream ) != 1 )
204     {
205         int             i_error;
206         if( (i_error = ferror( p_method->stream)) )
207         {
208             intf_ErrMsg( "Read 1 failed (%s)", strerror(i_error) );
209             p_input->b_error = 1;
210             return;
211         }
212
213         if( feof( p_method->stream ) )
214         {
215             intf_ErrMsg( "EOF reached" );
216             p_input->b_error = 1;
217             return;
218         }
219     }
220
221     if( U32_AT(p_header) == 0x1BA )
222     {
223         if( i_packet_size == 8 )
224         {
225             /* MPEG-2 stuffing bytes */
226             byte_t      p_garbage[8];
227             if( (p_data->p_buffer[13] & 0x7) != 0 )
228             {
229                 /* FIXME: catch EINTR ! */
230                 fread( p_garbage, p_garbage[0] & 0x7, 1,
231                        p_method->stream );
232             }
233         }
234     }
235
236     memset( p_packets, 0, sizeof(p_packets) );
237     p_packets[0] = p_data;
238 }
239
240
241 /*
242  * Packet management utilities
243  */
244
245 /*****************************************************************************
246  * NewPacket: allocates a data packet
247  *****************************************************************************/
248 static struct data_packet_s * NewPacket( void * p_garbage,
249                                          size_t i_size )
250 {
251     data_packet_t * p_data;
252
253     if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
254     {
255         intf_DbgMsg( "Out of memory" );
256         return NULL;
257     }
258
259     if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
260     {
261         intf_DbgMsg( "Out of memory" );
262         free( p_data );
263         return NULL;
264     }
265
266     p_data->p_payload_start = p_data->p_buffer;
267     p_data->p_payload_end = p_data->p_buffer + i_size;
268
269     return( p_data );
270 }
271
272 /*****************************************************************************
273  * NewPES: allocates a pes packet
274  *****************************************************************************/
275 static pes_packet_t * NewPES( void * p_garbage )
276 {
277     pes_packet_t * p_pes;
278
279     if( (p_pes = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL )
280     {
281         intf_DbgMsg( "Out of memory" );
282         return NULL;
283     }
284
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;
289
290     return( p_pes );
291 }
292
293 /*****************************************************************************
294  * DeletePacket: deletes a data packet
295  *****************************************************************************/
296 static void DeletePacket( void * p_garbage,
297                           data_packet_t * p_data )
298 {
299     ASSERT(p_data);
300     ASSERT(p_data->p_buffer);
301     free( p_data->p_buffer );
302     free( p_data );
303 }
304
305 /*****************************************************************************
306  * DeletePES: deletes a PES packet and associated data packets
307  *****************************************************************************/
308 static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
309 {
310     data_packet_t *     p_data;
311     data_packet_t *     p_next;
312
313     p_data = p_pes->p_first;
314
315     while( p_data != NULL )
316     {
317         p_next = p_data->p_next;
318         free( p_data->p_buffer );
319         free( p_data );
320         p_data = p_next;
321     }
322
323     free( p_pes );
324 }
325
326 /*****************************************************************************
327  * PSKludge: fakes a PS plugin (FIXME)
328  *****************************************************************************/
329 input_capabilities_t * PSKludge( void )
330 {
331     input_capabilities_t *  p_plugin;
332
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;
343
344     return( p_plugin );
345 }