-/* input_dvd.c: DVD raw reading plugin.
+/* dvd_access.c: DVD access plugin.
*****************************************************************************
* This plugins should handle all the known specificities of the DVD format,
* especially the 2048 bytes logical block size.
* -dvd_udf to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
- * $Id: input_dvd.c,v 1.132 2002/03/05 17:46:33 stef Exp $
+ * $Id: dvd_access.c,v 1.1 2002/03/06 01:20:56 stef Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
# include <strings.h>
#endif
-#if defined( WIN32 )
-# include <io.h> /* read() */
-#endif
-
#ifdef GOD_DAMN_DMCA
# include "dummy_dvdcss.h"
#else
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
-#include "input_dvd.h"
+#include "dvd.h"
+#include "dvd_es.h"
+#include "dvd_seek.h"
#include "dvd_ifo.h"
#include "dvd_summary.h"
#include "iso_lang.h"
#include "debug.h"
-/* how many packets DVDDemux will read in each loop */
-#define DVD_READ_ONCE 64
-
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int DVDRead ( struct input_thread_s *, byte_t *, size_t );
static void DVDSeek ( struct input_thread_s *, off_t );
-static int DVDRewind ( struct input_thread_s * );
-static int DVDDemux ( struct input_thread_s * );
-static int DVDInit ( struct input_thread_s * );
-static void DVDEnd ( struct input_thread_s * );
-
-/* called only inside */
-static void DVDLaunchDecoders( input_thread_t * p_input );
-static int DVDChooseAngle( thread_dvd_data_t * );
-static int DVDFindCell( thread_dvd_data_t * );
-static int DVDFindSector( thread_dvd_data_t * );
-static int DVDChapterSelect( thread_dvd_data_t *, int );
+static char * DVDParse( input_thread_t * );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
#undef input
}
-void _M( demux_getfunctions)( function_list_t * p_function_list )
-{
-#define demux p_function_list->functions.demux
- demux.pf_init = DVDInit;
- demux.pf_end = DVDEnd;
- demux.pf_demux = DVDDemux;
- demux.pf_rewind = DVDRewind;
-#undef demux
-}
-
-/*
- * Data demux functions
- */
-
-/*****************************************************************************
- * DVDInit: initializes DVD structures
- *****************************************************************************/
-static int DVDInit( input_thread_t * p_input )
-{
-
- if( strncmp( p_input->p_access_module->psz_name, "dvd", 3 ) )
- {
- return -1;
- }
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- DVDLaunchDecoders( p_input );
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- return 0;
-}
-
-/*****************************************************************************
- * DVDEnd: frees unused data
- *****************************************************************************/
-static void DVDEnd( input_thread_t * p_input )
-{
-}
-
-/*****************************************************************************
- * DVDDemux
- *****************************************************************************/
-#define PEEK( SIZE ) \
- i_result = input_Peek( p_input, &p_peek, SIZE ); \
- if( i_result == -1 ) \
- { \
- return( -1 ); \
- } \
- else if( i_result < SIZE ) \
- { \
- /* EOF */ \
- return( 0 ); \
- }
-
-static int DVDDemux( input_thread_t * p_input )
-{
- int i;
- byte_t * p_peek;
- data_packet_t * p_data;
- ssize_t i_result;
- int i_packet_size;
-
-
- /* Read headers to compute payload length */
- for( i = 0 ; i < DVD_READ_ONCE ; i++ )
- {
-
- /* Read what we believe to be a packet header. */
- PEEK( 4 );
-
- /* Default header */
- if( U32_AT( p_peek ) != 0x1BA )
- {
- /* That's the case for all packets, except pack header. */
- i_packet_size = U16_AT( p_peek + 4 );
- }
- else
- {
- /* MPEG-2 Pack header. */
- i_packet_size = 8;
- }
-
- /* Fetch a packet of the appropriate size. */
- i_result = input_SplitBuffer( p_input, &p_data, i_packet_size + 6 );
- if( i_result <= 0 )
- {
- return( i_result );
- }
-
- /* In MPEG-2 pack headers we still have to read stuffing bytes. */
- if( (p_data->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
- {
- size_t i_stuffing = (p_data->p_demux_start[13] & 0x7);
- /* Force refill of the input buffer - though we don't care
- * about p_peek. Please note that this is unoptimized. */
- PEEK( i_stuffing );
- p_input->p_current_data += i_stuffing;
- }
-
- input_DemuxPS( p_input, p_data );
-
- }
-
- return i;
-}
-
-/*****************************************************************************
- * DVDRewind : reads a stream backward
- *****************************************************************************/
-static int DVDRewind( input_thread_t * p_input )
-{
- return( -1 );
-}
-
-
-
/*
* Data access functions
*/
*****************************************************************************/
static int DVDOpen( struct input_thread_s *p_input )
{
- struct stat stat_info;
- char * psz_orig;
- char * psz_parser;
char * psz_device;
- char * psz_raw;
- char * psz_next;
dvdcss_handle dvdhandle;
thread_dvd_data_t * p_dvd;
input_area_t * p_area;
- boolean_t b_options = 0;
- int i_title = 1;
- int i_chapter = 1;
- int i_angle = 1;
int i;
- psz_orig = psz_parser = psz_device = strdup( p_input->psz_name );
- if( !psz_orig )
- {
- return( -1 );
- }
-
-
- /* Parse input string :
- * [device][@rawdevice][@[title][,[chapter][,angle]]] */
- while( *psz_parser && *psz_parser != '@' )
- {
- psz_parser++;
- }
-
- if( *psz_parser == '@' )
- {
- /* Maybe found raw device or option list */
- *psz_parser = '\0';
- psz_raw = ++psz_parser;
- }
- else
- {
- psz_raw = NULL;
- }
-
- if( *psz_parser && !strtol( psz_parser, NULL, 10 ) )
- {
- /* what we've found is either a raw device or a partial option
- * list e.g. @,29 or both a device and a list ; search end of string */
- while( *psz_parser && *psz_parser != '@' )
- {
- psz_parser++;
- }
-
- if( *psz_parser == '@' )
- {
- /* found end of raw device, and beginning of options */
- *psz_parser = '\0';
- ++psz_parser;
- b_options = 1;
- }
- else
- {
- psz_parser = psz_raw + 1;
- for( i=0 ; i<3 ; i++ )
- {
- if( !*psz_parser )
- {
- /* we have only a raw device */
- break;
- }
- if( strtol( psz_parser, NULL, 10 ) )
- {
- /* we have only a partial list of options, no device */
- psz_parser = psz_raw;
- psz_raw = NULL;
- b_options = 1;
- break;
- }
- psz_parser++;
- }
- }
- }
- else
- {
- /* found beginning of options ; no raw device specified */
- psz_raw = NULL;
- b_options = 1;
- }
-
- if( b_options )
- {
- /* Found options */
- i_title = (int)strtol( psz_parser, &psz_next, 10 );
- if( *psz_next )
- {
- psz_parser = psz_next + 1;
- i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
- if( *psz_next )
- {
- i_angle = (int)strtol( psz_next + 1, NULL, 10 );
- }
- }
-
- i_title = i_title ? i_title : 1;
- i_chapter = i_chapter ? i_chapter : 1;
- i_angle = i_angle ? i_angle : 1;
- }
-
- if( psz_raw )
- {
- if( *psz_raw )
- {
- /* check the raw device */
- if( stat( psz_raw, &stat_info ) == -1 )
- {
- intf_WarnMsg( 3, "dvd warning: cannot stat() raw"
- " device `%s' (%s)",
- psz_raw, strerror(errno));
- /* put back '@' */
- *(psz_raw - 1) = '@';
- psz_raw = NULL;
- }
- else
- {
- char * psz_env;
-
-#ifndef WIN32
- if( !S_ISCHR(stat_info.st_mode) )
- {
- intf_WarnMsg( 3, "dvd warning: raw device %s is"
- " not a valid char device", psz_raw );
- /* put back '@' */
- *(psz_raw - 1) = '@';
- psz_raw = NULL;
- }
- else
-#endif
- {
- psz_env = malloc( strlen("DVDCSS_RAW_DEVICE=")
- + strlen( psz_raw ) + 1 );
- sprintf( psz_env, "DVDCSS_RAW_DEVICE=%s", psz_raw );
- putenv( psz_env );
- }
- }
- }
- else
- {
- psz_raw = NULL;
- }
- }
-
- if( !*psz_device )
- {
- if( !p_input->psz_access )
- {
- /* no device and no access specified: we probably don't want DVD */
- free( psz_orig );
- return -1;
- }
- psz_device = config_GetPszVariable( INPUT_DVD_DEVICE_VAR );
- }
-
- /* check block device */
- if( stat( psz_device, &stat_info ) == -1 )
- {
- intf_ErrMsg( "input error: cannot stat() device `%s' (%s)",
- psz_device, strerror(errno));
- return( -1 );
- }
-
-#ifndef WIN32
- if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
+ p_dvd = malloc( sizeof(thread_dvd_data_t) );
+ if( p_dvd == NULL )
{
- intf_WarnMsg( 3, "input: DVD plugin discarded"
- " (not a valid block device)" );
+ intf_ErrMsg( "dvd error: out of memory" );
return -1;
}
-#endif
+ p_input->p_access_data = (void *)p_dvd;
- if( psz_raw )
+ /* Parse command line */
+ if( !( psz_device = DVDParse( p_input ) ) )
{
+ free( p_dvd );
+ return -1;
}
-
- intf_WarnMsg( 2, "input: dvd=%s raw=%s title=%d chapter=%d angle=%d",
- psz_device, psz_raw, i_title, i_chapter, i_angle );
/*
* set up input
*/
p_input->i_mtu = 0;
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- p_input->stream.i_method = INPUT_METHOD_DVD;
-
- /* If we are here we can control the pace... */
- p_input->stream.b_pace_control = 1;
-
- p_input->stream.b_seekable = 1;
- p_input->stream.p_selected_area->i_size = 0;
-
- p_input->stream.p_selected_area->i_tell = 0;
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
/*
* get plugin ready
*/
dvdhandle = dvdcss_open( psz_device );
- /* free allocated strings */
- if( psz_device != psz_orig )
- free( psz_device );
- free( psz_orig );
+ /* free allocated string */
+ free( psz_device );
if( dvdhandle == NULL )
return -1;
}
- p_dvd = malloc( sizeof(thread_dvd_data_t) );
- if( p_dvd == NULL )
- {
- intf_ErrMsg( "dvd error: out of memory" );
- return -1;
- }
-
p_dvd->dvdhandle = (dvdcss_handle) dvdhandle;
- p_input->p_access_data = (void *)p_dvd;
if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
{
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.i_method = INPUT_METHOD_DVD;
+ p_input->stream.b_pace_control = 1;
+ p_input->stream.b_seekable = 1;
+ p_input->stream.p_selected_area->i_size = 0;
+ p_input->stream.p_selected_area->i_tell = 0;
+
/* Initialize ES structures */
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
#define title_inf p_dvd->p_ifo->vmg.title_inf
- intf_WarnMsg( 2, "dvd info: number of titles: %d", title_inf.i_title_nb );
+ intf_WarnMsg( 3, "dvd info: number of titles: %d", title_inf.i_title_nb );
#define area p_input->stream.pp_areas
/* We start from 1 here since the default area 0
}
#undef area
- p_dvd->i_title = i_title <= title_inf.i_title_nb ? i_title : 1;
+ p_dvd->i_title = p_dvd->i_title <= title_inf.i_title_nb ?
+ p_dvd->i_title : 1;
#undef title_inf
-
p_area = p_input->stream.pp_areas[p_dvd->i_title];
- p_dvd->i_chapter = i_chapter < p_area->i_part_nb ? i_chapter : 1;
+ p_dvd->i_chapter = p_dvd->i_chapter < p_area->i_part_nb ?
+ p_dvd->i_chapter : 1;
p_area->i_part = p_dvd->i_chapter;
- p_dvd->i_angle = i_angle;
-
+ p_dvd->i_audio_nb = 0;
+ p_dvd->i_spu_nb = 0;
+
/* set title, chapter, audio and subpic */
if( DVDSetArea( p_input, p_area ) )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
return 0;
-
}
/*****************************************************************************
}
/*****************************************************************************
- * DVDSetProgram: Does nothing, a DVD is mono-program
+ * DVDSetProgram: used to change angle
*****************************************************************************/
static int DVDSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
i_angle = p_program->i_number;
+ /* DVD is actually mono-program: we only need the current angle
+ * number, so copy the data between programs */
memcpy( p_program, p_input->stream.p_selected_program,
sizeof(pgrm_descriptor_t) );
p_program->i_number = i_angle;
static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
{
thread_dvd_data_t * p_dvd;
- es_descriptor_t * p_es;
- u16 i_id;
int i_vts_title;
- int i_audio_nb = 0;
- int i_spu_nb = 0;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
{
/* Reset the Chapter position of the old title */
p_input->stream.p_selected_area->i_part = 0;
+ p_input->stream.p_selected_area = p_area;
/*
* We have to load all title information
*/
/* Change the default area */
- p_input->stream.p_selected_area =
- p_input->stream.pp_areas[p_area->i_id];
/* title number: it is not vts nb!,
* it is what appears in the interface list */
intf_WarnMsg( 3, "dvd: title %d vts_title %d pgc %d",
p_dvd->i_title, i_vts_title, p_dvd->i_title_id );
- /*
- * Angle management
- */
- p_dvd->i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
- if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
- {
- p_dvd->i_angle = 1;
- }
-
+
/*
* Set selected title start and size
*/
p_input->stream.p_selected_area->i_start = LB2OFF( p_dvd->i_start );
p_input->stream.p_selected_area->i_size = LB2OFF( p_dvd->i_size );
-#if 0
- /* start at the beginning of the title */
- /* FIXME: create a conf option to select whether to restart
- * title or not */
- p_input->stream.p_selected_area->i_tell = 0;
- p_input->stream.p_selected_area->i_part = 1;
-#endif
-
/*
* Destroy obsolete ES by reinitializing programs
* and find all ES in title with ifo data
{
/* We don't use input_EndStream here since
* we keep area structures */
-
- /* Unselect all ES */
- /*
- for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ )
+ while( p_input->stream.i_es_number )
{
- input_UnselectES( p_input, p_input->stream.pp_selected_es[i] );
+ input_DelES( p_input, p_input->stream.pp_es[0] );
}
-*/
- for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
+ while( p_input->stream.i_pgrm_number )
{
- input_DelES( p_input, p_input->stream.pp_es[i] );
- }
-
- for( i = 0 ; i < p_input->stream.i_pgrm_number ; i++ )
- {
- input_DelProgram( p_input, p_input->stream.pp_programs[i] );
+ input_DelProgram( p_input, p_input->stream.pp_programs[0] );
}
if( p_input->stream.pp_selected_es )
}
p_input->stream.i_selected_es_number = 0;
}
-
- /* angle */
-
+
+ /*
+ * Angle management: angles are handled through programs
+ */
+ p_dvd->i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
+ if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
+ {
+ p_dvd->i_angle = 1;
+ }
+
input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
/* No PSM to read in DVD mode, we already have all information */
p_input->stream.p_selected_program->b_is_ok = 1;
- p_es = NULL;
-
- /* ES 0 -> video MPEG2 */
- IfoPrintVideo( p_dvd );
-
- p_es = input_AddES( p_input, NULL, 0xe0, 0 );
- p_es->i_stream_id = 0xe0;
- p_es->i_type = MPEG2_VIDEO_ES;
- p_es->i_cat = VIDEO_ES;
+ DVDReadVideo( p_input );
-#define audio_status \
- vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1]
- /* Audio ES, in the order they appear in .ifo */
- for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
- {
- IfoPrintAudio( p_dvd, i );
-
- /* audio channel is active if first byte is 0x80 */
- if( audio_status.i_available )
- {
- i_audio_nb++;
-
- switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode )
- {
- case 0x00: /* AC3 */
- i_id = ( ( 0x80 + audio_status.i_position ) << 8 ) | 0xbd;
- p_es = input_AddES( p_input, NULL, i_id, 0 );
- p_es->i_stream_id = 0xbd;
- p_es->i_type = AC3_AUDIO_ES;
- p_es->b_audio = 1;
- p_es->i_cat = AUDIO_ES;
- strcpy( p_es->psz_desc, DecodeLanguage( hton16(
- vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) );
- strcat( p_es->psz_desc, " (ac3)" );
-
- break;
- case 0x02:
- case 0x03: /* MPEG audio */
- i_id = 0xc0 + audio_status.i_position;
- p_es = input_AddES( p_input, NULL, i_id, 0 );
- p_es->i_stream_id = i_id;
- p_es->i_type = MPEG2_AUDIO_ES;
- p_es->b_audio = 1;
- p_es->i_cat = AUDIO_ES;
- strcpy( p_es->psz_desc, DecodeLanguage( hton16(
- vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) );
- strcat( p_es->psz_desc, " (mpeg)" );
-
- break;
- case 0x04: /* LPCM */
-
- i_id = ( ( 0xa0 + audio_status.i_position ) << 8 ) | 0xbd;
- p_es = input_AddES( p_input, NULL, i_id, 0 );
- p_es->i_stream_id = 0xbd;
- p_es->i_type = LPCM_AUDIO_ES;
- p_es->b_audio = 1;
- p_es->i_cat = AUDIO_ES;
- strcpy( p_es->psz_desc, DecodeLanguage( hton16(
- vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) );
- strcat( p_es->psz_desc, " (lpcm)" );
-
- break;
- case 0x06: /* DTS */
- i_id = ( ( 0x88 + audio_status.i_position ) << 8 ) | 0xbd;
- intf_ErrMsg( "dvd warning: DTS audio not handled yet"
- "(0x%x)", i_id );
- break;
- default:
- i_id = 0;
- intf_ErrMsg( "dvd warning: unknown audio type %.2x",
- vts.manager_inf.p_audio_attr[i-1].i_coding_mode );
- }
- }
- }
-#undef audio_status
-#define spu_status \
- vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1]
-
- /* Sub Picture ES */
-
- for( i = 1 ; i <= vts.manager_inf.i_spu_nb; i++ )
- {
- IfoPrintSpu( p_dvd, i );
-
- if( spu_status.i_available )
- {
- i_spu_nb++;
-
- /* there are several streams for one spu */
- if( vts.manager_inf.video_attr.i_ratio )
- {
- /* 16:9 */
- switch( vts.manager_inf.video_attr.i_perm_displ )
- {
- case 1:
- i_id = ( ( 0x20 + spu_status.i_position_pan ) << 8 )
- | 0xbd;
- break;
- case 2:
- i_id = ( ( 0x20 + spu_status.i_position_letter ) << 8 )
- | 0xbd;
- break;
- default:
- i_id = ( ( 0x20 + spu_status.i_position_wide ) << 8 )
- | 0xbd;
- break;
- }
- }
- else
- {
- /* 4:3 */
- i_id = ( ( 0x20 + spu_status.i_position_43 ) << 8 )
- | 0xbd;
- }
- p_es = input_AddES( p_input, NULL, i_id, 0 );
- p_es->i_stream_id = 0xbd;
- p_es->i_type = DVD_SPU_ES;
- p_es->i_cat = SPU_ES;
- strcpy( p_es->psz_desc, DecodeLanguage( hton16(
- vts.manager_inf.p_spu_attr[i-1].i_lang_code ) ) );
- }
- }
-#undef spu_status
-
+ DVDReadAudio( p_input );
+
+ DVDReadSPU( p_input );
+
/* FIXME: hack to check that the demuxer is ready, and set
* the decoders */
if( p_input->p_demux_module )
return -1;
}
+ p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
p_input->stream.p_selected_area->i_tell =
LB2OFF( p_dvd->i_start ) - p_area->i_start;
- p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
intf_WarnMsg( 4, "dvd info: chapter %d start at: %lld",
p_area->i_part, p_area->i_tell );
}
}
-#define title \
- p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
-
/* warn interface that something has changed */
p_input->stream.b_seekable = 1;
p_input->stream.b_changed = 1;
return 0;
}
+#define title \
+ p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
/*****************************************************************************
* DVDRead: reads data packets.
p_dvd->i_title_start + p_dvd->i_sector,
DVDCSS_SEEK_MPEG ) ) < 0 )
{
- intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
+ intf_ErrMsg( "dvd error: %s",
+ dvdcss_error( p_dvd->dvdhandle ) );
return -1;
}
{
i_block_once = i_blocks;
}
- /*
- intf_WarnMsg( 2, "Sector: 0x%x Read: %d Chapter: %d", p_dvd->i_sector, i_block_once, p_dvd->i_chapter );
- */
/* Reads from DVD */
i_read_blocks = dvdcss_read( p_dvd->dvdhandle, p_buffer,
intf_WarnMsg( 4, "dvd info: new title" );
p_dvd->i_title++;
DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return LB2OFF( i_read_total );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
-/*
- if( i_read_blocks != i_block_once )
- {
- return -1;
- }
-*/
+
return LB2OFF( i_read_total );
}
LB2OFF ( i_block ) - p_input->stream.p_selected_area->i_start;
vlc_mutex_unlock( &p_input->stream.stream_lock );
- intf_WarnMsg( 7, "Program Cell: %d Cell: %d Chapter: %d",
+ intf_WarnMsg( 4, "Program Cell: %d Cell: %d Chapter: %d",
p_dvd->i_prg_cell, p_dvd->i_cell, p_dvd->i_chapter );
return;
}
-#define cell p_dvd->p_ifo->vts.cell_inf
-
/*****************************************************************************
- * DVDFindCell: adjust the title cell index with the program cell
+ * DVDParse: parse command line
*****************************************************************************/
-static int DVDFindCell( thread_dvd_data_t * p_dvd )
+static char * DVDParse( input_thread_t * p_input )
{
- int i_cell;
- int i_index;
-
- i_cell = p_dvd->i_cell;
- i_index = p_dvd->i_prg_cell;
+ thread_dvd_data_t * p_dvd;
+ struct stat stat_info;
+ char * psz_parser;
+ char * psz_device;
+ char * psz_raw;
+ char * psz_next;
+ boolean_t b_options = 0;
+ int i_title = 1;
+ int i_chapter = 1;
+ int i_angle = 1;
+ int i;
+
+ p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
- if( i_cell >= cell.i_cell_nb )
+ psz_parser = psz_device = strdup( p_input->psz_name );
+ if( !psz_parser )
{
- return -1;
+ return NULL;
}
- while( ( ( title.p_cell_pos[i_index].i_vob_id !=
- cell.p_cell_map[i_cell].i_vob_id ) ||
- ( title.p_cell_pos[i_index].i_cell_id !=
- cell.p_cell_map[i_cell].i_cell_id ) ) &&
- ( i_cell < cell.i_cell_nb - 1 ) )
+ /* Parse input string :
+ * [device][@rawdevice][@[title][,[chapter][,angle]]] */
+ while( *psz_parser && *psz_parser != '@' )
{
- i_cell++;
+ psz_parser++;
}
-/*
-intf_WarnMsg( 12, "FindCell: i_cell %d i_index %d found %d nb %d",
- p_dvd->i_cell,
- p_dvd->i_prg_cell,
- i_cell,
- cell.i_cell_nb );
-*/
-
- p_dvd->i_cell = i_cell;
-
- return 0;
-}
-
-#undef cell
-
-/*****************************************************************************
- * DVDFindSector: find cell index in adress map from index in
- * information table program map and give corresponding sectors.
- *****************************************************************************/
-static int DVDFindSector( thread_dvd_data_t * p_dvd )
-{
-
- if( p_dvd->i_sector > title.p_cell_play[p_dvd->i_prg_cell].i_end_sector )
+ if( *psz_parser == '@' )
{
- p_dvd->i_prg_cell++;
-
- if( DVDChooseAngle( p_dvd ) < 0 )
- {
- return -1;
- }
+ /* Maybe found raw device or option list */
+ *psz_parser = '\0';
+ psz_raw = ++psz_parser;
}
-
- if( DVDFindCell( p_dvd ) < 0 )
+ else
{
- intf_ErrMsg( "dvd error: can't find sector" );
- return -1;
+ psz_raw = NULL;
}
-
- /* Find start and end sectors of new cell */
-#if 1
- p_dvd->i_sector = __MAX(
- p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_start_sector,
- title.p_cell_play[p_dvd->i_prg_cell].i_start_sector );
- p_dvd->i_end_sector = __MIN(
- p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector,
- title.p_cell_play[p_dvd->i_prg_cell].i_end_sector );
-#else
- p_dvd->i_sector = title.p_cell_play[p_dvd->i_prg_cell].i_start_sector;
- p_dvd->i_end_sector = title.p_cell_play[p_dvd->i_prg_cell].i_end_sector;
-#endif
-
-/*
- intf_WarnMsg( 12, "cell: %d sector1: 0x%x end1: 0x%x\n"
- "index: %d sector2: 0x%x end2: 0x%x\n"
- "category: 0x%x ilvu end: 0x%x vobu start 0x%x",
- p_dvd->i_cell,
- p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_start_sector,
- p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector,
- p_dvd->i_prg_cell,
- title.p_cell_play[p_dvd->i_prg_cell].i_start_sector,
- title.p_cell_play[p_dvd->i_prg_cell].i_end_sector,
- title.p_cell_play[p_dvd->i_prg_cell].i_category,
- title.p_cell_play[p_dvd->i_prg_cell].i_first_ilvu_vobu_esector,
- title.p_cell_play[p_dvd->i_prg_cell].i_last_vobu_start_sector );
-*/
-
- return 0;
-}
-
-/*****************************************************************************
- * DVDChapterSelect: find the cell corresponding to requested chapter
- *****************************************************************************/
-static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
-{
-
- /* Find cell index in Program chain for current chapter */
- p_dvd->i_prg_cell = title.chapter_map.pi_start_cell[i_chapter-1] - 1;
- p_dvd->i_cell = 0;
- p_dvd->i_sector = 0;
- DVDChooseAngle( p_dvd );
-
- /* Search for cell_index in cell adress_table and initialize
- * start sector */
- if( DVDFindSector( p_dvd ) < 0 )
+ if( *psz_parser && !strtol( psz_parser, NULL, 10 ) )
{
- intf_ErrMsg( "dvd error: can't select chapter" );
- return -1;
+ /* what we've found is either a raw device or a partial option
+ * list e.g. @,29 or both a device and a list ; search end of string */
+ while( *psz_parser && *psz_parser != '@' )
+ {
+ psz_parser++;
+ }
+
+ if( *psz_parser == '@' )
+ {
+ /* found end of raw device, and beginning of options */
+ *psz_parser = '\0';
+ ++psz_parser;
+ b_options = 1;
+ }
+ else
+ {
+ psz_parser = psz_raw + 1;
+ for( i=0 ; i<3 ; i++ )
+ {
+ if( !*psz_parser )
+ {
+ /* we have only a raw device */
+ break;
+ }
+ if( strtol( psz_parser, NULL, 10 ) )
+ {
+ /* we have only a partial list of options, no device */
+ psz_parser = psz_raw;
+ psz_raw = NULL;
+ b_options = 1;
+ break;
+ }
+ psz_parser++;
+ }
+ }
}
-
- /* start is : beginning of vts vobs + offset to vob x */
- p_dvd->i_start = p_dvd->i_title_start + p_dvd->i_sector;
-
- /* Position the fd pointer on the right address */
- if( ( p_dvd->i_start = dvdcss_seek( p_dvd->dvdhandle,
- p_dvd->i_start,
- DVDCSS_SEEK_MPEG ) ) < 0 )
+ else
{
- intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
- return -1;
+ /* found beginning of options ; no raw device specified */
+ psz_raw = NULL;
+ b_options = 1;
}
- p_dvd->i_chapter = i_chapter;
- return 0;
-}
-
-/*****************************************************************************
- * DVDChooseAngle: select the cell corresponding to the selected angle
- *****************************************************************************/
-static int DVDChooseAngle( thread_dvd_data_t * p_dvd )
-{
- /* basic handling of angles */
- switch( ( ( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
- >> 12 ) )
+ if( b_options )
{
- /* we enter a muli-angle section */
- case 0x5:
- p_dvd->i_prg_cell += p_dvd->i_angle - 1;
- p_dvd->i_angle_cell = 0;
- break;
- /* we exit a multi-angle section */
- case 0x9:
- case 0xd:
- p_dvd->i_prg_cell += p_dvd->i_angle_nb - p_dvd->i_angle;
- break;
- }
-
- return 0;
-}
-
-#undef title
-/*****************************************************************************
- * DVDLaunchDecoders
- *****************************************************************************/
-static void DVDLaunchDecoders( input_thread_t * p_input )
-{
- thread_dvd_data_t * p_dvd;
- int i_audio;
- int i_spu;
-
- p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
+ /* Found options */
+ i_title = (int)strtol( psz_parser, &psz_next, 10 );
+ if( *psz_next )
+ {
+ psz_parser = psz_next + 1;
+ i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
+ if( *psz_next )
+ {
+ i_angle = (int)strtol( psz_next + 1, NULL, 10 );
+ }
+ }
- /* Select Video stream (always 0) */
- if( p_main->b_video )
- {
- input_SelectES( p_input, p_input->stream.pp_es[0] );
+ p_dvd->i_title = i_title ? i_title : 1;
+ p_dvd->i_chapter = i_chapter ? i_chapter : 1;
+ p_dvd->i_angle = i_angle ? i_angle : 1;
}
- /* Select audio stream */
- if( p_main->b_audio )
+ if( psz_raw )
{
- /* For audio: first one if none or a not existing one specified */
- i_audio = config_GetIntVariable( INPUT_CHANNEL_VAR );
- if( i_audio < 0 /*|| i_audio > i_audio_nb*/ )
- {
- config_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
- i_audio = 1;
- }
- if( i_audio > 0 /*&& i_audio_nb > 0*/ )
+ if( *psz_raw )
{
- if( config_GetIntVariable( AOUT_SPDIF_VAR ) ||
- ( config_GetIntVariable( INPUT_AUDIO_VAR ) ==
- REQUESTED_AC3 ) )
+ /* check the raw device */
+ if( stat( psz_raw, &stat_info ) == -1 )
+ {
+ intf_WarnMsg( 3, "dvd warning: cannot stat() raw"
+ " device `%s' (%s)",
+ psz_raw, strerror(errno));
+ /* put back '@' */
+ *(psz_raw - 1) = '@';
+ psz_raw = NULL;
+ }
+ else
{
- int i_ac3 = i_audio;
- while( ( p_input->stream.pp_es[i_ac3]->i_type !=
- AC3_AUDIO_ES ) && ( i_ac3 <=
- p_dvd->p_ifo->vts.manager_inf.i_audio_nb ) )
+ char * psz_env;
+
+#ifndef WIN32
+ if( !S_ISCHR(stat_info.st_mode) )
{
- i_ac3++;
+ intf_WarnMsg( 3, "dvd warning: raw device %s is"
+ " not a valid char device", psz_raw );
+ /* put back '@' */
+ *(psz_raw - 1) = '@';
+ psz_raw = NULL;
}
- if( p_input->stream.pp_es[i_ac3]->i_type == AC3_AUDIO_ES )
+ else
+#endif
{
- input_SelectES( p_input,
- p_input->stream.pp_es[i_ac3] );
+ psz_env = malloc( strlen("DVDCSS_RAW_DEVICE=")
+ + strlen( psz_raw ) + 1 );
+ sprintf( psz_env, "DVDCSS_RAW_DEVICE=%s", psz_raw );
+ putenv( psz_env );
}
}
- else
- {
- input_SelectES( p_input,
- p_input->stream.pp_es[i_audio] );
- }
}
- }
-
- /* Select subtitle */
- if( p_main->b_video )
- {
- /* for spu, default is none */
- i_spu = config_GetIntVariable( INPUT_SUBTITLE_VAR );
- if( i_spu < 0 /*|| i_spu > i_spu_nb*/ )
+ else
{
- config_PutIntVariable( INPUT_SUBTITLE_VAR, 0 );
- i_spu = 0;
+ psz_raw = NULL;
}
- if( i_spu > 0 /* && i_spu_nb > 0*/ )
+ }
+
+ if( !*psz_device )
+ {
+ free( psz_device );
+
+ if( !p_input->psz_access )
{
- i_spu += p_dvd->p_ifo->vts.manager_inf.i_audio_nb;
- input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
+ /* no device and no access specified: we probably don't want DVD */
+ return NULL;
}
+ psz_device = config_GetPszVariable( INPUT_DVD_DEVICE_VAR );
}
-}
+
+ /* check block device */
+ if( stat( psz_device, &stat_info ) == -1 )
+ {
+ intf_ErrMsg( "input error: cannot stat() device `%s' (%s)",
+ psz_device, strerror(errno));
+ return NULL;
+ }
+
+#ifndef WIN32
+ if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
+ {
+ intf_WarnMsg( 3, "input: DVD plugin discarded"
+ " (not a valid block device)" );
+ return NULL;
+ }
+#endif
+
+ intf_WarnMsg( 2, "input: dvd=%s raw=%s title=%d chapter=%d angle=%d",
+ psz_device, psz_raw, p_dvd->i_title,
+ p_dvd->i_chapter, p_dvd->i_angle );
+
+ return psz_device;
+}