]> git.sesse.net Git - vlc/blob - plugins/vcd/input_vcd.c
* Modified vcd input for the new input III.
[vlc] / plugins / vcd / input_vcd.c
1 /****************************************************************************
2  * input_vcd.c: VideoCD raw reading plugin.
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  *
6  * Author: Johan Bilien <jobi@via.ecp.fr>
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 <stdio.h>
27 #include <stdlib.h>
28
29 #include <videolan/vlc.h>
30
31 #ifdef HAVE_UNISTD_H
32 #   include <unistd.h>
33 #endif
34
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <string.h>
38 #include <errno.h>
39
40 #ifdef STRNCASECMP_IN_STRINGS_H
41 #   include <strings.h>
42 #endif
43
44 #if defined( WIN32 )
45 #   include <io.h>                                                 /* read() */
46 #else
47 #   include <sys/uio.h>                                      /* struct iovec */
48 #endif
49
50 #if defined( WIN32 )
51 #   include "input_iovec.h"
52 #endif
53
54 #include "stream_control.h"
55 #include "input_ext-intf.h"
56 #include "input_ext-dec.h"
57 #include "input_ext-plugins.h"
58
59 #include "debug.h"
60
61 #include "input_vcd.h"
62 #include "cdrom_tools.h"
63
64 /* how many blocks VCDRead will read in each loop */
65 #define VCD_BLOCKS_ONCE 20
66 #define VCD_DATA_ONCE   (VCD_BLOCKS_ONCE * VCD_DATA_SIZE)
67
68 /*****************************************************************************
69  * Local prototypes
70  *****************************************************************************/
71 /* called from outside */
72 static int  VCDInit         ( struct input_thread_s * );
73 static void VCDEnd          ( struct input_thread_s * );
74 static int  PSDemux        ( struct input_thread_s * );
75 static int  VCDRewind       ( struct input_thread_s * );
76
77 static int  VCDOpen         ( struct input_thread_s *);
78 static void VCDClose        ( struct input_thread_s *);
79 static int  VCDRead         ( struct input_thread_s *, byte_t *, size_t );
80 static void VCDSeek         ( struct input_thread_s *, off_t );
81 static int  VCDSetArea      ( struct input_thread_s *, struct input_area_s * );
82 static int  VCDSetProgram   ( struct input_thread_s *, pgrm_descriptor_t * );
83
84 static ssize_t PSRead       ( struct input_thread_s *, data_packet_t ** );
85 /*****************************************************************************
86  * Functions exported as capabilities. They are declared as static so that
87  * we don't pollute the namespace too much.
88  *****************************************************************************/
89 void _M( access_getfunctions )( function_list_t * p_function_list )
90 {
91 #define access p_function_list->functions.access
92     access.pf_open             = VCDOpen;
93     access.pf_close            = VCDClose;
94     access.pf_read             = VCDRead;
95     access.pf_set_area         = VCDSetArea;
96     access.pf_set_program      = VCDSetProgram;
97     access.pf_seek             = VCDSeek;
98 #undef access
99 }
100
101
102 void _M( demux_getfunctions )( function_list_t * p_function_list )
103 {
104 #define demux p_function_list->functions.demux
105     demux.pf_init             = VCDInit;
106     demux.pf_end              = VCDEnd;
107     demux.pf_demux            = PSDemux;
108     demux.pf_rewind           = VCDRewind;
109 #undef demux
110 }
111
112 /*
113  * Data reading functions
114  */
115
116 /*****************************************************************************
117  * VCDOpen: open vcd
118  *****************************************************************************/
119 static int VCDOpen( struct input_thread_s *p_input )
120 {
121     char *                  psz_orig;
122     char *                  psz_parser;
123     char *                  psz_source;
124     char *                  psz_next;
125     thread_vcd_data_t *  p_vcd;
126     int                  i;
127     input_area_t *       p_area;
128     int                  i_title = 1;
129     int                  i_chapter = 1;
130
131     p_vcd = malloc( sizeof(thread_vcd_data_t) );
132
133     if( p_vcd == NULL )
134     {
135         intf_ErrMsg( "vcd error: out of memory" );
136         p_input->b_error = 1;
137         return -1;
138     }
139
140     p_input->i_mtu = VCD_DATA_ONCE;
141     p_input->p_access_data = (void *)p_vcd;
142
143     /* parse the options passed in command line : */
144     psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
145     
146     if( !psz_orig )
147     {
148         return( -1 );
149     }
150  
151     while( *psz_parser && *psz_parser != '@' )
152     {
153         psz_parser++;
154     }
155
156     if( *psz_parser == '@' )
157     {
158         /* Found options */
159         *psz_parser = '\0';
160         ++psz_parser;
161
162         i_title = (int)strtol( psz_parser, &psz_next, 10 );
163         if( *psz_next )
164         {
165             psz_parser = psz_next + 1;
166             i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
167         }
168
169         i_title = i_title ? i_title : 1;
170         i_chapter = i_chapter ? i_chapter : 1;
171     }
172
173     if( !*psz_source )
174     {
175         if( !p_input->psz_access )
176         {
177             free( psz_orig );
178             return -1;
179         }
180         psz_source = config_GetPszVariable( INPUT_VCD_DEVICE_VAR );
181     }
182  
183     vlc_mutex_lock( &p_input->stream.stream_lock );
184
185     /* If we are here we can control the pace... */
186     p_input->stream.b_pace_control = 1;
187
188     p_input->stream.b_seekable = 1;
189     p_input->stream.p_selected_area->i_size = 0;
190     p_input->stream.p_selected_area->i_tell = 0;
191
192     vlc_mutex_unlock( &p_input->stream.stream_lock );
193
194     p_vcd->i_handle = open( psz_source, O_RDONLY | O_NONBLOCK );
195
196     if( p_vcd->i_handle == -1 )
197     {
198         intf_ErrMsg( "input: vcd: Could not open %s\n", psz_source );
199         p_input->b_error = 1;
200         free (p_vcd);
201         return -1;
202     }
203
204     /* We read the Table Of Content information */
205     p_vcd->nb_tracks = ioctl_GetTrackCount( p_vcd->i_handle,
206                                             psz_source );
207     if( p_vcd->nb_tracks < 0 )
208     {
209         intf_ErrMsg( "input: vcd: was unable to count tracks" );
210         free( p_vcd );
211         p_input->b_error = 1;
212         return -1;
213     }
214     else if( p_vcd->nb_tracks <= 1 )
215     {
216         intf_ErrMsg( "input: vcd: no movie tracks found" );
217         free( p_vcd );
218         p_input->b_error = 1;
219         return -1;
220     }
221
222     p_vcd->p_sectors = ioctl_GetSectors( p_vcd->i_handle,
223                                          psz_source );
224     if ( p_vcd->p_sectors == NULL )
225     {
226         input_BuffersEnd( p_input->p_method_data );
227         free( p_vcd );
228         p_input->b_error = 1;
229         return -1;
230     }
231
232     /* Set stream and area data */
233     vlc_mutex_lock( &p_input->stream.stream_lock );
234
235     /* Initialize ES structures */
236     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
237
238     /* disc input method */
239     p_input->stream.i_method = INPUT_METHOD_VCD;
240
241 #define area p_input->stream.pp_areas
242     for( i = 1 ; i <= p_vcd->nb_tracks - 1 ; i++ )
243     {
244         input_AddArea( p_input );
245
246         /* Titles are Program Chains */
247         area[i]->i_id = i;
248
249         /* Absolute start offset and size */
250         area[i]->i_start = (off_t)p_vcd->p_sectors[i] * (off_t)VCD_DATA_SIZE;
251         area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
252                            * (off_t)VCD_DATA_SIZE;
253
254         /* Number of chapters */
255         area[i]->i_part_nb = 0;   // will be the entry points
256         area[i]->i_part = 1;
257
258         area[i]->i_plugin_data = p_vcd->p_sectors[i];
259     }
260 #undef area
261
262     p_area = p_input->stream.pp_areas[i_title];
263
264     VCDSetArea( p_input, p_area );
265
266     vlc_mutex_unlock( &p_input->stream.stream_lock );
267
268     return 0;
269 }
270
271     
272
273 /*****************************************************************************
274  * VCDClose: closes vcd
275  *****************************************************************************/
276 static void VCDClose( struct input_thread_s *p_input )
277 {
278     thread_vcd_data_t *     p_vcd
279         = (thread_vcd_data_t *)p_input->p_access_data;
280     close( p_vcd->i_handle );
281     free( p_vcd );
282 }
283
284 /*****************************************************************************
285  * VCDRead: reads from the VCD into PES packets.
286  *****************************************************************************
287  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
288  * bytes.
289  *****************************************************************************/
290 static int VCDRead( input_thread_t * p_input, byte_t * p_buffer, 
291                      size_t i_len )
292 {
293     thread_vcd_data_t *     p_vcd;
294     int                     i_blocks;
295     int                     i_index;
296     int                     i_read;
297     byte_t                  p_last_sector[ VCD_DATA_SIZE ];
298
299     p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
300
301     i_read = 0;
302
303     /* Compute the number of blocks we have to read */
304
305     i_blocks = i_len / VCD_DATA_SIZE;
306
307     for ( i_index = 0 ; i_index < i_blocks ; i_index++ ) 
308     {
309         if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector, 
310                     p_buffer + i_index * VCD_DATA_SIZE ) < 0 )
311         {
312             intf_ErrMsg( "input: vcd: could not read sector %d\n", 
313                     p_vcd->i_sector );
314             return -1;
315         }
316
317         p_vcd->i_sector ++;
318         if ( p_vcd->i_sector == p_vcd->p_sectors[p_vcd->i_track + 1] )
319         {
320             /* FIXME we should go to next track */
321             return 0;
322         }
323         i_read += VCD_DATA_SIZE;
324     }
325     
326     if ( i_len % VCD_DATA_SIZE ) /* this should not happen */
327     { 
328         if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector, 
329                     p_last_sector ) < 0 )
330         {
331             intf_ErrMsg( "input: vcd: could not read sector %d\n", 
332                     p_vcd->i_sector );
333             return -1;
334         }
335         
336         FAST_MEMCPY( p_buffer + i_blocks * VCD_DATA_SIZE,
337                     p_last_sector, i_len % VCD_DATA_SIZE );
338         i_read += i_len % VCD_DATA_SIZE;
339     }
340     
341     p_input->stream.p_selected_area->i_tell = 
342         (off_t)p_vcd->i_sector * (off_t)VCD_DATA_SIZE
343          - p_input->stream.p_selected_area->i_start;
344
345     return i_read;
346 }
347
348
349 /*****************************************************************************
350  * VCDSetProgram: Does nothing since a VCD is mono_program
351  *****************************************************************************/
352 static int VCDSetProgram( input_thread_t * p_input,
353                           pgrm_descriptor_t * p_program)
354 {
355     return 0;
356 }
357
358
359 /*****************************************************************************
360  * VCDSetArea: initialize input data for title x, chapter y.
361  * It should be called for each user navigation request.
362  ****************************************************************************/
363 static int VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
364 {
365     thread_vcd_data_t *     p_vcd;
366
367     p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
368
369     /* we can't use the interface slider until initilization is complete */
370     p_input->stream.b_seekable = 0;
371
372     if( p_area != p_input->stream.p_selected_area )
373     {
374         /* Reset the Chapter position of the current title */
375         p_input->stream.p_selected_area->i_part = 1;
376         p_input->stream.p_selected_area->i_tell = 0;
377
378         /* Change the default area */
379         p_input->stream.p_selected_area = p_area;
380
381         /* Change the current track */
382         /* The first track is not a valid one  */
383         p_vcd->i_track = p_area->i_id;
384         p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track];
385     }
386
387     /* warn interface that something has changed */
388     p_input->stream.b_seekable = 1;
389     p_input->stream.b_changed = 1;
390
391     return 0;
392 }
393
394
395 /*****************************************************************************
396  * VCDRewind : reads a stream backward
397  *****************************************************************************/
398 static int VCDRewind( input_thread_t * p_input )
399 {
400     return( -1 );
401 }
402
403 /****************************************************************************
404  * VCDSeek
405  ****************************************************************************/
406 static void VCDSeek( input_thread_t * p_input, off_t i_off )
407 {
408     thread_vcd_data_t *               p_vcd;
409
410     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
411
412     p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track]
413                        + i_off / (off_t)VCD_DATA_SIZE;
414
415     p_input->stream.p_selected_area->i_tell = 
416         (off_t)p_vcd->i_sector * (off_t)VCD_DATA_SIZE
417          - p_input->stream.p_selected_area->i_start;
418 }
419
420 /*
421  * Demux functions
422  */
423
424
425 /*****************************************************************************
426  * VCDInit: initializes VCD structures
427  *****************************************************************************/
428 static int VCDInit( input_thread_t * p_input )
429 {
430     es_descriptor_t *       p_es;
431     
432     /* Set program information. */
433
434     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
435     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
436
437     /* No PSM to read in disc mode, we already have all the information */
438     p_input->stream.p_selected_program->b_is_ok = 1;
439
440     p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xe0, 0 );
441     p_es->i_stream_id = 0xe0;
442     p_es->i_type = MPEG1_VIDEO_ES;
443     p_es->i_cat = VIDEO_ES;
444
445     if( p_main->b_video )
446     {
447         input_SelectES( p_input, p_es );
448     }
449
450     p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xc0, 0 );
451     p_es->i_stream_id = 0xc0;
452     p_es->i_type = MPEG1_AUDIO_ES;
453     p_es->b_audio = 1;
454     p_es->i_cat = AUDIO_ES;
455
456     if( p_main->b_audio )
457     {
458         input_SelectES( p_input, p_es );
459     }
460
461     vlc_mutex_unlock( &p_input->stream.stream_lock );
462     
463     return 0;
464 }
465
466 /*****************************************************************************
467  * VCDEnd: frees unused data
468  *****************************************************************************/
469 static void VCDEnd( input_thread_t * p_input )
470 {
471     thread_vcd_data_t *     p_vcd;
472
473     input_BuffersEnd( p_input->p_method_data );
474
475     p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
476
477     free( p_vcd );
478 }
479
480
481 /*****************************************************************************
482  * The following functions are extracted from mpeg_ps, they should soon
483  * be placed in mpeg_system.c so that plugins can use them.
484  *****************************************************************************/
485
486 /*****************************************************************************
487  * PSRead: reads one PS packet
488  *****************************************************************************/
489 #define PEEK( SIZE )                                                        \
490     i_error = input_Peek( p_input, &p_peek, SIZE );                         \
491     if( i_error == -1 )                                                     \
492     {                                                                       \
493         return( -1 );                                                       \
494     }                                                                       \
495     else if( i_error < SIZE )                                               \
496     {                                                                       \
497         /* EOF */                                                           \
498         return( 0 );                                                        \
499     }
500
501 static __inline__ ssize_t PSRead( input_thread_t * p_input,
502                                   data_packet_t ** pp_data )
503 {
504     byte_t *            p_peek;
505     size_t              i_packet_size;
506     ssize_t             i_error, i_read;
507
508     /* Read what we believe to be a packet header. */
509     PEEK( 4 );
510
511     if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
512     {
513         if( *p_peek || *(p_peek + 1) || *(p_peek + 2) )
514         {
515             /* It is common for MPEG-1 streams to pad with zeros
516              * (although it is forbidden by the recommendation), so
517              * don't bother everybody in this case. */
518             intf_WarnMsg( 3, "input warning: garbage at input (0x%x%x%x%x)",
519                  *p_peek, *(p_peek + 1), *(p_peek + 2), *(p_peek + 3) );
520         }
521
522         /* This is not the startcode of a packet. Read the stream
523          * until we find one. */
524         while( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
525         {
526             p_input->p_current_data++;
527             PEEK( 4 );
528         }
529         /* Packet found. */
530     }
531
532     /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
533     if( p_peek[3] != 0xB9 )
534     {
535         /* The packet is at least 6 bytes long. */
536         PEEK( 6 );
537
538         if( p_peek[3] != 0xBA )
539         {
540             /* That's the case for all packets, except pack header. */
541             i_packet_size = (p_peek[4] << 8) | p_peek[5];
542         }
543         else
544         {
545             /* Pack header. */
546             if( (p_peek[4] & 0xC0) == 0x40 )
547             {
548                 /* MPEG-2 */
549                 i_packet_size = 8;
550             }
551             else if( (p_peek[4] & 0xF0) == 0x20 )
552             {
553                 /* MPEG-1 */
554                 i_packet_size = 6;
555             }
556             else
557             {
558                 intf_ErrMsg( "Unable to determine stream type" );
559                 return( -1 );
560             }
561         }
562     }
563     else
564     {
565         /* System End Code */
566         i_packet_size = -2;
567     }
568
569     /* Fetch a packet of the appropriate size. */
570     i_read = input_SplitBuffer( p_input, pp_data, i_packet_size + 6 );
571     if( i_read <= 0 )
572     {
573         return( i_read );
574     }
575
576     /* In MPEG-2 pack headers we still have to read stuffing bytes. */
577     if( ((*pp_data)->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
578     {
579         size_t i_stuffing = ((*pp_data)->p_demux_start[13] & 0x7);
580         /* Force refill of the input buffer - though we don't care
581          * about p_peek. Please note that this is unoptimized. */
582         PEEK( i_stuffing );
583         p_input->p_current_data += i_stuffing;
584     }
585
586     return( 1 );
587 }
588
589 /*****************************************************************************
590  * PSDemux: reads and demuxes data packets
591  *****************************************************************************
592  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
593  * packets.
594  *****************************************************************************/
595 static int PSDemux( input_thread_t * p_input )
596 {
597     int                 i;
598
599     for( i = 0; i < VCD_BLOCKS_ONCE; i++ )
600     {
601         data_packet_t *     p_data;
602         ssize_t             i_result;
603
604         i_result = PSRead( p_input, &p_data );
605
606         if( i_result <= 0 )
607         {
608             return( i_result );
609         }
610
611         input_DemuxPS( p_input, p_data );
612     }
613
614     return( i );
615 }
616