1 /****************************************************************************
2 * input_vcd.c: VideoCD raw reading plugin.
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
6 * Author: Johan Bilien <jobi@via.ecp.fr>
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 <videolan/vlc.h>
36 #include <sys/types.h>
40 #ifdef STRNCASECMP_IN_STRINGS_H
45 # include <io.h> /* read() */
47 # include <sys/uio.h> /* struct iovec */
51 # include "input_iovec.h"
54 #include "stream_control.h"
55 #include "input_ext-intf.h"
56 #include "input_ext-dec.h"
57 #include "input_ext-plugins.h"
61 #include "input_vcd.h"
62 #include "cdrom_tools.h"
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)
68 /*****************************************************************************
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 * );
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 * );
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 )
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;
102 void _M( demux_getfunctions )( function_list_t * p_function_list )
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;
113 * Data reading functions
116 /*****************************************************************************
118 *****************************************************************************/
119 static int VCDOpen( struct input_thread_s *p_input )
125 thread_vcd_data_t * p_vcd;
127 input_area_t * p_area;
131 p_vcd = malloc( sizeof(thread_vcd_data_t) );
135 intf_ErrMsg( "vcd error: out of memory" );
136 p_input->b_error = 1;
140 p_input->i_mtu = VCD_DATA_ONCE;
141 p_input->p_access_data = (void *)p_vcd;
143 /* parse the options passed in command line : */
144 psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
151 while( *psz_parser && *psz_parser != '@' )
156 if( *psz_parser == '@' )
162 i_title = (int)strtol( psz_parser, &psz_next, 10 );
165 psz_parser = psz_next + 1;
166 i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
169 i_title = i_title ? i_title : 1;
170 i_chapter = i_chapter ? i_chapter : 1;
175 if( !p_input->psz_access )
180 psz_source = config_GetPszVariable( INPUT_VCD_DEVICE_VAR );
183 vlc_mutex_lock( &p_input->stream.stream_lock );
185 /* If we are here we can control the pace... */
186 p_input->stream.b_pace_control = 1;
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;
192 vlc_mutex_unlock( &p_input->stream.stream_lock );
194 p_vcd->i_handle = open( psz_source, O_RDONLY | O_NONBLOCK );
196 if( p_vcd->i_handle == -1 )
198 intf_ErrMsg( "input: vcd: Could not open %s\n", psz_source );
199 p_input->b_error = 1;
204 /* We read the Table Of Content information */
205 p_vcd->nb_tracks = ioctl_GetTrackCount( p_vcd->i_handle,
207 if( p_vcd->nb_tracks < 0 )
209 intf_ErrMsg( "input: vcd: was unable to count tracks" );
211 p_input->b_error = 1;
214 else if( p_vcd->nb_tracks <= 1 )
216 intf_ErrMsg( "input: vcd: no movie tracks found" );
218 p_input->b_error = 1;
222 p_vcd->p_sectors = ioctl_GetSectors( p_vcd->i_handle,
224 if ( p_vcd->p_sectors == NULL )
226 input_BuffersEnd( p_input->p_method_data );
228 p_input->b_error = 1;
232 /* Set stream and area data */
233 vlc_mutex_lock( &p_input->stream.stream_lock );
235 /* Initialize ES structures */
236 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
238 /* disc input method */
239 p_input->stream.i_method = INPUT_METHOD_VCD;
241 #define area p_input->stream.pp_areas
242 for( i = 1 ; i <= p_vcd->nb_tracks - 1 ; i++ )
244 input_AddArea( p_input );
246 /* Titles are Program Chains */
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;
254 /* Number of chapters */
255 area[i]->i_part_nb = 0; // will be the entry points
258 area[i]->i_plugin_data = p_vcd->p_sectors[i];
262 p_area = p_input->stream.pp_areas[i_title];
264 VCDSetArea( p_input, p_area );
266 vlc_mutex_unlock( &p_input->stream.stream_lock );
273 /*****************************************************************************
274 * VCDClose: closes vcd
275 *****************************************************************************/
276 static void VCDClose( struct input_thread_s *p_input )
278 thread_vcd_data_t * p_vcd
279 = (thread_vcd_data_t *)p_input->p_access_data;
280 close( p_vcd->i_handle );
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
289 *****************************************************************************/
290 static int VCDRead( input_thread_t * p_input, byte_t * p_buffer,
293 thread_vcd_data_t * p_vcd;
297 byte_t p_last_sector[ VCD_DATA_SIZE ];
299 p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
303 /* Compute the number of blocks we have to read */
305 i_blocks = i_len / VCD_DATA_SIZE;
307 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
309 if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector,
310 p_buffer + i_index * VCD_DATA_SIZE ) < 0 )
312 intf_ErrMsg( "input: vcd: could not read sector %d\n",
318 if ( p_vcd->i_sector == p_vcd->p_sectors[p_vcd->i_track + 1] )
320 /* FIXME we should go to next track */
323 i_read += VCD_DATA_SIZE;
326 if ( i_len % VCD_DATA_SIZE ) /* this should not happen */
328 if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector,
329 p_last_sector ) < 0 )
331 intf_ErrMsg( "input: vcd: could not read sector %d\n",
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;
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;
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)
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 )
365 thread_vcd_data_t * p_vcd;
367 p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
369 /* we can't use the interface slider until initilization is complete */
370 p_input->stream.b_seekable = 0;
372 if( p_area != p_input->stream.p_selected_area )
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;
378 /* Change the default area */
379 p_input->stream.p_selected_area = p_area;
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];
387 /* warn interface that something has changed */
388 p_input->stream.b_seekable = 1;
389 p_input->stream.b_changed = 1;
395 /*****************************************************************************
396 * VCDRewind : reads a stream backward
397 *****************************************************************************/
398 static int VCDRewind( input_thread_t * p_input )
403 /****************************************************************************
405 ****************************************************************************/
406 static void VCDSeek( input_thread_t * p_input, off_t i_off )
408 thread_vcd_data_t * p_vcd;
410 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
412 p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track]
413 + i_off / (off_t)VCD_DATA_SIZE;
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;
425 /*****************************************************************************
426 * VCDInit: initializes VCD structures
427 *****************************************************************************/
428 static int VCDInit( input_thread_t * p_input )
430 es_descriptor_t * p_es;
432 /* Set program information. */
434 input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
435 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
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;
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;
445 if( p_main->b_video )
447 input_SelectES( p_input, p_es );
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;
454 p_es->i_cat = AUDIO_ES;
456 if( p_main->b_audio )
458 input_SelectES( p_input, p_es );
461 vlc_mutex_unlock( &p_input->stream.stream_lock );
466 /*****************************************************************************
467 * VCDEnd: frees unused data
468 *****************************************************************************/
469 static void VCDEnd( input_thread_t * p_input )
471 thread_vcd_data_t * p_vcd;
473 input_BuffersEnd( p_input->p_method_data );
475 p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
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 *****************************************************************************/
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 ) \
495 else if( i_error < SIZE ) \
501 static __inline__ ssize_t PSRead( input_thread_t * p_input,
502 data_packet_t ** pp_data )
505 size_t i_packet_size;
506 ssize_t i_error, i_read;
508 /* Read what we believe to be a packet header. */
511 if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
513 if( *p_peek || *(p_peek + 1) || *(p_peek + 2) )
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) );
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 )
526 p_input->p_current_data++;
532 /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
533 if( p_peek[3] != 0xB9 )
535 /* The packet is at least 6 bytes long. */
538 if( p_peek[3] != 0xBA )
540 /* That's the case for all packets, except pack header. */
541 i_packet_size = (p_peek[4] << 8) | p_peek[5];
546 if( (p_peek[4] & 0xC0) == 0x40 )
551 else if( (p_peek[4] & 0xF0) == 0x20 )
558 intf_ErrMsg( "Unable to determine stream type" );
565 /* System End Code */
569 /* Fetch a packet of the appropriate size. */
570 i_read = input_SplitBuffer( p_input, pp_data, i_packet_size + 6 );
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) )
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. */
583 p_input->p_current_data += i_stuffing;
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
594 *****************************************************************************/
595 static int PSDemux( input_thread_t * p_input )
599 for( i = 0; i < VCD_BLOCKS_ONCE; i++ )
601 data_packet_t * p_data;
604 i_result = PSRead( p_input, &p_data );
611 input_DemuxPS( p_input, p_data );