]> git.sesse.net Git - vlc/blob - plugins/mpeg/input_ps.c
First serie of changes in DVD module for the forthcoming interface menus
[vlc] / plugins / mpeg / input_ps.c
1 /*****************************************************************************
2  * input_ps.c: PS demux and packet management
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000 VideoLAN
5  * $Id: input_ps.c,v 1.7 2001/02/20 02:53:13 stef Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "defs.h"
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #include "config.h"
39 #include "common.h"
40 #include "threads.h"
41 #include "mtime.h"
42 #include "tests.h"
43
44 #include "intf_msg.h"
45
46 #include "main.h"
47
48 #include "stream_control.h"
49 #include "input_ext-intf.h"
50 #include "input_ext-dec.h"
51
52 #include "input.h"
53
54 #include "input_ps.h"
55 #include "mpeg_system.h"
56
57 #include "debug.h"
58
59 #include "modules.h"
60
61 /*****************************************************************************
62  * Local prototypes
63  *****************************************************************************/
64 static int  PSProbe     ( probedata_t * );
65 static int  PSRead      ( struct input_thread_s *,
66                           data_packet_t * p_packets[INPUT_READ_ONCE] );
67 static void PSInit      ( struct input_thread_s * );
68 static void PSEnd       ( struct input_thread_s * );
69 static void PSSeek      ( struct input_thread_s *, off_t );
70 static struct pes_packet_s *  NewPES    ( void * );
71 static struct data_packet_s * NewPacket ( void *, size_t );
72 static void DeletePacket( void *, struct data_packet_s * );
73 static void DeletePES   ( void *, struct pes_packet_s * );
74
75 /*****************************************************************************
76  * Functions exported as capabilities. They are declared as static so that
77  * we don't pollute the namespace too much.
78  *****************************************************************************/
79 void input_getfunctions( function_list_t * p_function_list )
80 {
81 #define input p_function_list->functions.input
82     p_function_list->pf_probe = PSProbe;
83     input.pf_init             = PSInit;
84     input.pf_open             = input_FileOpen;
85     input.pf_close            = input_FileClose;
86     input.pf_end              = PSEnd;
87     input.pf_set_area         = NULL;
88     input.pf_read             = PSRead;
89     input.pf_demux            = input_DemuxPS;
90     input.pf_new_packet       = NewPacket;
91     input.pf_new_pes          = NewPES;
92     input.pf_delete_packet    = DeletePacket;
93     input.pf_delete_pes       = DeletePES;
94     input.pf_rewind           = NULL;
95     input.pf_seek             = PSSeek;
96 #undef input
97 }
98
99 /*
100  * Data reading functions
101  */
102
103 /*****************************************************************************
104  * PSProbe: verifies that the stream is a PS stream
105  *****************************************************************************/
106 static int PSProbe( probedata_t *p_data )
107 {
108     input_thread_t * p_input = (input_thread_t *)p_data;
109
110     char * psz_name = p_input->p_source;
111     int i_handle;
112     int i_score = 10;
113
114     if( TestMethod( INPUT_METHOD_VAR, "ps" ) )
115     {
116         return( 999 );
117     }
118
119     if( ( strlen(psz_name) > 5 ) && !strncasecmp( psz_name, "file:", 5 ) )
120     {
121         /* If the user specified "file:" then it's probably a file */
122         i_score = 100;
123         psz_name += 5;
124     }
125
126     i_handle = open( psz_name, 0 );
127     if( i_handle == -1 )
128     {
129         return( 0 );
130     }
131     close( i_handle );
132
133     return( i_score );
134 }
135
136 /*****************************************************************************
137  * PSInit: initializes PS structures
138  *****************************************************************************/
139 static void PSInit( input_thread_t * p_input )
140 {
141     thread_ps_data_t *  p_method;
142
143     if( (p_method =
144          (thread_ps_data_t *)malloc( sizeof(thread_ps_data_t) )) == NULL )
145     {
146         intf_ErrMsg( "Out of memory" );
147         p_input->b_error = 1;
148         return;
149     }
150
151     p_input->p_plugin_data = (void *)p_method;
152     p_input->p_method_data = NULL;
153
154     /* Re-open the socket as a buffered FILE stream */
155     if( (p_method->stream = fdopen( p_input->i_handle, "r" )) == NULL )
156     {
157         intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
158         p_input->b_error = 1;
159         return;
160     }
161     rewind( p_method->stream );
162
163     /* FIXME : detect if InitStream failed */
164     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
165     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
166
167     if( p_input->stream.b_seekable )
168     {
169         stream_ps_data_t * p_demux_data =
170              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
171
172         /* Pre-parse the stream to gather stream_descriptor_t. */
173         p_input->stream.pp_programs[0]->b_is_ok = 0;
174         p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
175
176         while( !p_input->b_die && !p_input->b_error
177                 && !p_demux_data->b_has_PSM )
178         {
179             int                 i_result, i;
180             data_packet_t *     pp_packets[INPUT_READ_ONCE];
181
182             i_result = PSRead( p_input, pp_packets );
183             if( i_result == 1 )
184             {
185                 /* EOF */
186                 vlc_mutex_lock( &p_input->stream.stream_lock );
187                 p_input->stream.pp_programs[0]->b_is_ok = 1;
188                 vlc_mutex_unlock( &p_input->stream.stream_lock );
189                 break;
190             }
191             if( i_result == -1 )
192             {
193                 p_input->b_error = 1;
194                 break;
195             }
196
197             for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
198             {
199                 /* FIXME: use i_p_config_t */
200                 input_ParsePS( p_input, pp_packets[i] );
201                 DeletePacket( p_input->p_method_data, pp_packets[i] );
202             }
203
204             /* File too big. */
205             if( p_input->stream.pp_areas[0]->i_tell > INPUT_PREPARSE_LENGTH )
206             {
207                 break;
208             }
209         }
210         rewind( p_method->stream );
211         vlc_mutex_lock( &p_input->stream.stream_lock );
212         p_input->stream.pp_areas[0]->i_tell = 0;
213         if( p_demux_data->b_has_PSM )
214         {
215             /* (The PSM decoder will care about spawning the decoders) */
216             p_input->stream.pp_programs[0]->b_is_ok = 1;
217         }
218 #ifdef AUTO_SPAWN
219         else
220         {
221             /* (We have to do it ourselves) */
222             int                 i_es;
223
224             /* FIXME: we should do multiple passes in case an audio type
225              * is not present */
226             for( i_es = 0;
227                  i_es < p_input->stream.pp_programs[0]->i_es_number;
228                  i_es++ )
229             {
230 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
231                 switch( p_es->i_type )
232                 {
233                     case MPEG1_VIDEO_ES:
234                     case MPEG2_VIDEO_ES:
235                         input_SelectES( p_input, p_es );
236                         break;
237
238                     case MPEG1_AUDIO_ES:
239                     case MPEG2_AUDIO_ES:
240                         if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
241                                 == (p_es->i_id & 0x1F) )
242                         switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
243                         {
244                         case 0:
245                             main_PutIntVariable( INPUT_AUDIO_VAR,
246                                                  REQUESTED_MPEG );
247                         case REQUESTED_MPEG:
248                             input_SelectES( p_input, p_es );
249                         }
250                         break;
251
252                     case AC3_AUDIO_ES:
253                         if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
254                                 == ((p_es->i_id & 0xF00) >> 8) )
255                         switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
256                         {
257                         case 0:
258                             main_PutIntVariable( INPUT_AUDIO_VAR,
259                                                  REQUESTED_AC3 );
260                         case REQUESTED_AC3:
261                             input_SelectES( p_input, p_es );
262                         }
263                         break;
264
265                     case DVD_SPU_ES:
266                         if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
267                                 == ((p_es->i_id & 0x1F00) >> 8) )
268                         {
269                             input_SelectES( p_input, p_es );
270                         }
271                         break;
272
273                     case LPCM_AUDIO_ES:
274                         /* FIXME ! */
275                         break;
276                 }
277             }
278                     
279         }
280 #endif
281 #ifdef STATS
282         input_DumpStream( p_input );
283 #endif
284         vlc_mutex_unlock( &p_input->stream.stream_lock );
285     }
286     else
287     {
288         /* The programs will be added when we read them. */
289         vlc_mutex_lock( &p_input->stream.stream_lock );
290         p_input->stream.pp_programs[0]->b_is_ok = 0;
291         vlc_mutex_unlock( &p_input->stream.stream_lock );
292     }
293 }
294
295 /*****************************************************************************
296  * PSEnd: frees unused data
297  *****************************************************************************/
298 static void PSEnd( input_thread_t * p_input )
299 {
300     free( p_input->stream.p_demux_data );
301     free( p_input->p_plugin_data );
302 }
303
304 /*****************************************************************************
305  * SafeRead: reads a chunk of stream and correctly detects errors
306  *****************************************************************************/
307 static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
308                                 size_t i_len )
309 {
310     thread_ps_data_t *  p_method;
311     int                 i_error;
312
313     p_method = (thread_ps_data_t *)p_input->p_plugin_data;
314     while( fread( p_buffer, i_len, 1, p_method->stream ) != 1 )
315     {
316         if( feof( p_method->stream ) )
317         {
318             return( 1 );
319         }
320
321         if( (i_error = ferror( p_method->stream )) )
322         {
323             intf_ErrMsg( "Read failed (%s)", strerror(i_error) );
324             return( -1 );
325         }
326     }
327     vlc_mutex_lock( &p_input->stream.stream_lock );
328     p_input->stream.pp_areas[0]->i_tell += i_len;
329     vlc_mutex_unlock( &p_input->stream.stream_lock );
330     return( 0 );
331 }
332
333 /*****************************************************************************
334  * PSRead: reads data packets
335  *****************************************************************************
336  * Returns -1 in case of error, 0 if everything went well, and 1 in case of
337  * EOF.
338  *****************************************************************************/
339 static int PSRead( input_thread_t * p_input,
340                    data_packet_t * pp_packets[INPUT_READ_ONCE] )
341 {
342     byte_t              p_header[6];
343     data_packet_t *     p_data;
344     size_t              i_packet_size;
345     int                 i_packet, i_error;
346     thread_ps_data_t *  p_method;
347
348     p_method = (thread_ps_data_t *)p_input->p_plugin_data;
349
350     memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
351     for( i_packet = 0; i_packet < INPUT_READ_ONCE; i_packet++ )
352     {
353         /* Read what we believe to be a packet header. */
354         if( (i_error = SafeRead( p_input, p_header, 6 )) )
355         {
356             return( i_error );
357         }
358
359         if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
360         {
361             /* This is not the startcode of a packet. Read the stream
362              * until we find one. */
363             u32         i_startcode = U32_AT(p_header);
364             int         i_dummy;
365
366             if( i_startcode )
367             {
368                 /* It is common for MPEG-1 streams to pad with zeros
369                  * (although it is forbidden by the recommendation), so
370                  * don't bother everybody in this case. */
371                 intf_WarnMsg( 1, "Garbage at input (%x)", i_startcode );
372             }
373
374             while( (i_startcode & 0xFFFFFF00) != 0x100L )
375             {
376                 i_startcode <<= 8;
377                 if( (i_dummy = getc( p_method->stream )) != EOF )
378                 {
379                     i_startcode |= i_dummy;
380                 }
381                 else
382                 {
383                     return( 1 );
384                 }
385             }
386             /* Packet found. */
387             *(u32 *)p_header = U32_AT(&i_startcode);
388             if( (i_error = SafeRead( p_input, p_header + 4, 2 )) )
389             {
390                 return( i_error );
391             }
392         }
393
394         if( U32_AT(p_header) != 0x1BA )
395         {
396             /* That's the case for all packets, except pack header. */
397             i_packet_size = U16_AT(&p_header[4]);
398         }
399         else
400         {
401             /* Pack header. */
402             if( (p_header[4] & 0xC0) == 0x40 )
403             {
404                 /* MPEG-2 */
405                 i_packet_size = 8;
406             }
407             else if( (p_header[4] & 0xF0) == 0x20 )
408             {
409                 /* MPEG-1 */
410                 i_packet_size = 6;
411             }
412             else
413             {
414                 intf_ErrMsg( "Unable to determine stream type" );
415                 return( -1 );
416             }
417         }
418
419         /* Fetch a packet of the appropriate size. */
420         if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
421         {
422             intf_ErrMsg( "Out of memory" );
423             return( -1 );
424         }
425
426         /* Copy the header we already read. */
427         memcpy( p_data->p_buffer, p_header, 6 );
428
429         /* Read the remaining of the packet. */
430         if( i_packet_size && (i_error =
431                 SafeRead( p_input, p_data->p_buffer + 6, i_packet_size )) )
432         {
433             return( i_error );
434         }
435
436         /* In MPEG-2 pack headers we still have to read stuffing bytes. */
437         if( U32_AT(p_header) == 0x1BA )
438         {
439             if( i_packet_size == 8 && (p_data->p_buffer[13] & 0x7) != 0 )
440             {
441                 /* MPEG-2 stuffing bytes */
442                 byte_t      p_garbage[8];
443                 if( (i_error = SafeRead( p_input, p_garbage,
444                                          p_data->p_buffer[13] & 0x7)) )
445                 {
446                     return( i_error );
447                 }
448             }
449         }
450
451         /* Give the packet to the other input stages. */
452         pp_packets[i_packet] = p_data;
453     }
454
455     return( 0 );
456 }
457
458 /*****************************************************************************
459  * PSSeek: changes the stream position indicator
460  *****************************************************************************/
461 static void PSSeek( input_thread_t * p_input, off_t i_position )
462 {
463     thread_ps_data_t *  p_method;
464
465     p_method = (thread_ps_data_t *)p_input->p_plugin_data;
466
467     /* A little bourrin but should work for a while --Meuuh */
468     fseeko( p_method->stream, i_position, SEEK_SET );
469
470     p_input->stream.pp_areas[0]->i_tell = i_position;
471 }
472
473 /*
474  * Packet management utilities
475  */
476
477 /*****************************************************************************
478  * NewPacket: allocates a data packet
479  *****************************************************************************/
480 static struct data_packet_s * NewPacket( void * p_garbage,
481                                          size_t i_size )
482 {
483     data_packet_t * p_data;
484
485     /* Safety check */
486     if( i_size > INPUT_MAX_PACKET_SIZE )
487     {
488         intf_ErrMsg( "Packet too big (%d)", i_size );
489         return NULL;
490     }
491
492     if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
493     {
494         intf_DbgMsg( "Out of memory" );
495         return NULL;
496     }
497
498     if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
499     {
500         intf_DbgMsg( "Out of memory" );
501         free( p_data );
502         return NULL;
503     }
504
505     /* Initialize data */
506     p_data->p_next = NULL;
507     p_data->b_discard_payload = 0;
508
509     p_data->p_payload_start = p_data->p_buffer;
510     p_data->p_payload_end = p_data->p_buffer + i_size;
511
512     return( p_data );
513 }
514
515 /*****************************************************************************
516  * NewPES: allocates a pes packet
517  *****************************************************************************/
518 static pes_packet_t * NewPES( void * p_garbage )
519 {
520     pes_packet_t * p_pes;
521
522     if( (p_pes = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL )
523     {
524         intf_DbgMsg( "Out of memory" );
525         return NULL;
526     }
527
528     p_pes->b_data_alignment = p_pes->b_discontinuity =
529         p_pes->i_pts = p_pes->i_dts = 0;
530     p_pes->i_pes_size = 0;
531     p_pes->p_first = NULL;
532
533     return( p_pes );
534 }
535
536 /*****************************************************************************
537  * DeletePacket: deletes a data packet
538  *****************************************************************************/
539 static void DeletePacket( void * p_garbage,
540                           data_packet_t * p_data )
541 {
542     ASSERT(p_data);
543     ASSERT(p_data->p_buffer);
544     free( p_data->p_buffer );
545     free( p_data );
546 }
547
548 /*****************************************************************************
549  * DeletePES: deletes a PES packet and associated data packets
550  *****************************************************************************/
551 static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
552 {
553     data_packet_t *     p_data;
554     data_packet_t *     p_next;
555
556     p_data = p_pes->p_first;
557
558     while( p_data != NULL )
559     {
560         p_next = p_data->p_next;
561         free( p_data->p_buffer );
562         free( p_data );
563         p_data = p_next;
564     }
565
566     free( p_pes );
567 }
568
569