From: Gildas Bazin Date: Fri, 20 Aug 2004 23:37:40 +0000 (+0000) Subject: * src/input/*, include/vlc_input.h: the MRL is now parsed for titles/chapters directl... X-Git-Tag: 0.8.0~638 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=25d2a663a98c0adc49d95e3ad5612f76da954953;p=vlc * src/input/*, include/vlc_input.h: the MRL is now parsed for titles/chapters directly in the core. - syntax is: [url][@[title-start][,chapter-start][-[title-end][,chapter-end]]] - core also handles start/end boundaries itself (simplifies the access plugins). * modules/access/dvdread.c,dvdnav.c,cdda.c: removed MRL parsing code. --- diff --git a/include/vlc_input.h b/include/vlc_input.h index 8ae8ce1b1f..48db4b6ee4 100644 --- a/include/vlc_input.h +++ b/include/vlc_input.h @@ -201,6 +201,14 @@ typedef struct int i_title; input_title_t **title; + int i_title_offset; + int i_seekpoint_offset; + + int i_title_start; + int i_title_end; + int i_seekpoint_start; + int i_seekpoint_end; + /* Properties */ vlc_bool_t b_can_pace_control; vlc_bool_t b_can_pause; @@ -253,6 +261,9 @@ struct input_thread_t int i_title; input_title_t **title; + int i_title_offset; + int i_seekpoint_offset; + /* User bookmarks FIXME won't be easy with multiples input */ int i_bookmark; seekpoint_t **bookmark; diff --git a/modules/access/cdda.c b/modules/access/cdda.c index a6e6cd9546..72ac171c2f 100644 --- a/modules/access/cdda.c +++ b/modules/access/cdda.c @@ -72,9 +72,6 @@ struct access_sys_t int i_titles; input_title_t *title[99]; /* No more that 99 track in a cd-audio */ - int i_title_start; - int i_title_end; - /* Current position */ int i_sector; /* Current Sector */ int * p_sectors; /* Track sectors */ @@ -90,54 +87,38 @@ static int Control( access_t *, int, va_list ); /***************************************************************************** * Open: open cdda - * MRL syntax: [dev_path][@[title-start][-[title-end]]] *****************************************************************************/ static int Open( vlc_object_t *p_this ) { access_t *p_access = (access_t*)p_this; access_sys_t *p_sys; - char *psz_dup, *psz; - int i, i_title_start = -1, i_title_end = -1; vcddev_t *vcddev; + char *psz_name; + int i; - /* Command line: [dev_path][@[title-start][-[title-end]]] */ - psz_dup = p_access->psz_path? strdup( p_access->psz_path ) : 0; - if( psz_dup && ( psz = strchr( psz_dup, '@' ) ) ) - { - *psz++ = 0; - i_title_start = i_title_end = strtol( psz, NULL, 0 ); - - if( ( psz = strchr( psz, '-' ) ) ) - { - *psz++; - i_title_end = strtol( psz, NULL, 0 ); - } - } - - if( !psz_dup || !*psz_dup ) + if( !p_access->psz_path || !*p_access->psz_path ) { - if( psz_dup ) free( psz_dup ); - /* Only when selected */ - if( !p_access->b_force ) return VLC_EGENERIC; + if( !p_this->b_force ) return VLC_EGENERIC; - psz_dup = var_CreateGetString( p_access, "cd-audio" ); - if( !psz_dup || !*psz_dup ) + psz_name = var_CreateGetString( p_this, "cd-audio" ); + if( !psz_name || !*psz_name ) { - if( psz_dup ) free( psz_dup ); + if( psz_name ) free( psz_name ); return VLC_EGENERIC; } } + else psz_name = strdup( p_access->psz_path ); /* Open CDDA */ - if( (vcddev = ioctl_Open( VLC_OBJECT(p_access), psz_dup )) == NULL ) + if( (vcddev = ioctl_Open( VLC_OBJECT(p_access), psz_name )) == NULL ) { - msg_Warn( p_access, "could not open %s", psz_dup ); - free( psz_dup ); + msg_Warn( p_access, "could not open %s", psz_name ); + free( psz_name ); return VLC_EGENERIC; } - free( psz_dup ); + free( psz_name ); /* Set up p_access */ p_access->pf_read = NULL; @@ -184,17 +165,8 @@ static int Open( vlc_object_t *p_this ) t->i_length = I64C(1000000) * t->i_size / 44100 / 4; } - /* Starting title and sector */ - if( i_title_start < 1 || i_title_start > p_sys->i_titles ) - p_sys->i_title_start = 1; - else p_sys->i_title_start = i_title_start; - if( i_title_end < 1 || i_title_end > p_sys->i_titles ) - p_sys->i_title_end = -1; - else p_sys->i_title_end = i_title_end; - - p_sys->i_sector = p_sys->p_sectors[p_sys->i_title_start-1]; - p_access->info.i_title = p_sys->i_title_start-1; - p_access->info.i_size = p_sys->title[p_sys->i_title_start-1]->i_size; + p_sys->i_sector = p_sys->p_sectors[0]; + p_access->info.i_size = p_sys->title[0]->i_size; /* Build a WAV header for the output data */ memset( &p_sys->waveheader, 0, sizeof(WAVEHEADER) ); @@ -266,9 +238,7 @@ static block_t *Block( access_t *p_access ) /* Check end of title */ while( p_sys->i_sector >= p_sys->p_sectors[p_access->info.i_title + 1] ) { - if( p_access->info.i_title + 1 >= p_sys->i_titles || - ( p_sys->i_title_end > 0 && - p_access->info.i_title + 1 >= p_sys->i_title_end ) ) + if( p_access->info.i_title + 1 >= p_sys->i_titles ) { p_access->info.b_eof = VLC_TRUE; return NULL; @@ -371,6 +341,7 @@ static int Control( access_t *p_access, int i_query, va_list args ) case ACCESS_GET_TITLE_INFO: ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); pi_int = (int*)va_arg( args, int* ); + *((int*)va_arg( args, int* )) = 1; /* Title offset */ /* Duplicate title infos */ *pi_int = p_sys->i_titles; @@ -394,10 +365,6 @@ static int Control( access_t *p_access, int i_query, va_list args ) /* Next sector to read */ p_sys->i_sector = p_sys->p_sectors[i]; - - /* User tries to access another title so better reset - * the end title */ - p_sys->i_title_end = -1; } break; diff --git a/modules/access/dvdnav.c b/modules/access/dvdnav.c index 2ff28cbf34..1ce2cf08a6 100644 --- a/modules/access/dvdnav.c +++ b/modules/access/dvdnav.c @@ -52,6 +52,10 @@ /***************************************************************************** * Module descriptor *****************************************************************************/ +#define ANGLE_TEXT N_("DVD angle") +#define ANGLE_LONGTEXT N_( \ + "Allows you to select the default DVD angle." ) + #define CACHING_TEXT N_("Caching value in ms") #define CACHING_LONGTEXT N_( \ "Allows you to modify the default caching value for DVDnav streams. This "\ @@ -66,6 +70,8 @@ static void Close( vlc_object_t * ); vlc_module_begin(); set_description( _("DVDnav Input") ); + add_integer( "dvdnav-angle", 1, NULL, ANGLE_TEXT, + ANGLE_LONGTEXT, VLC_FALSE ); add_integer( "dvdnav-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); add_bool( "dvdnav-menu", VLC_TRUE, NULL, @@ -82,8 +88,6 @@ vlc_module_end(); /***************************************************************************** * Local prototypes *****************************************************************************/ -static char *ParseCL( vlc_object_t *, char *, vlc_bool_t, int *, int *, int *); - typedef struct { VLC_COMMON_MEMBERS @@ -146,16 +150,28 @@ static int Open( vlc_object_t *p_this ) demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; dvdnav_t *p_dvdnav; - int i_title, i_chapter, i_angle; + int i_angle; char *psz_name; vlc_value_t val; - psz_name = ParseCL( VLC_OBJECT(p_demux), p_demux->psz_path, VLC_TRUE, - &i_title, &i_chapter, &i_angle ); - if( !psz_name ) + if( !p_demux->psz_path || !*p_demux->psz_path ) { - return VLC_EGENERIC; + /* Only when selected */ + if( !p_this->b_force ) return VLC_EGENERIC; + + psz_name = var_CreateGetString( p_this, "dvd" ); + if( !psz_name || !*psz_name ) + { + if( psz_name ) free( psz_name ); + return VLC_EGENERIC; + } } + else psz_name = strdup( p_demux->psz_path ); + +#ifdef WIN32 + if( psz_name[0] && psz_name[1] == ':' && + psz_name[2] == '\\' && psz_name[3] == '\0' ) psz_name[2] = '\0'; +#endif /* Try some simple probing to avoid going through dvdnav_open too often */ if( ProbeDVD( p_demux, psz_name ) != VLC_SUCCESS ) @@ -164,9 +180,6 @@ static int Open( vlc_object_t *p_this ) return VLC_EGENERIC; } - msg_Dbg( p_this, "dvdroot=%s title=%d chapter=%d angle=%d", - psz_name, i_title, i_chapter, i_angle ); - /* Open dvdnav */ if( dvdnav_open( &p_dvdnav, psz_name ) != DVDNAV_STATUS_OK ) { @@ -227,39 +240,9 @@ static int Open( vlc_object_t *p_this ) DemuxTitles( p_demux ); - /* Set forced title/chapter */ - if( i_title > 0 ) - { - if( dvdnav_title_play( p_sys->dvdnav, i_title ) != DVDNAV_STATUS_OK ) - { - msg_Warn( p_demux, "cannot set title" ); - i_title = 0; - } - else - { - p_demux->info.i_update |= INPUT_UPDATE_TITLE; - p_demux->info.i_title = i_title; - } - } - - if( i_chapter > 1 && i_title > 0 ) - { - if( dvdnav_part_play( p_sys->dvdnav, i_title, i_chapter ) != - DVDNAV_STATUS_OK ) - { - msg_Warn( p_demux, "cannot set chapter" ); - i_chapter = 1; - } - else - { - p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT; - p_demux->info.i_seekpoint = i_chapter; - } - } - var_Create( p_demux, "dvdnav-menu", VLC_VAR_BOOL|VLC_VAR_DOINHERIT ); var_Get( p_demux, "dvdnav-menu", &val ); - if( (i_title < 0 && val.b_bool) || i_title == 0 ) + if( val.b_bool ) { msg_Dbg( p_demux, "trying to go to dvd menu" ); @@ -273,15 +256,12 @@ static int Open( vlc_object_t *p_this ) { msg_Warn( p_demux, "cannot go to dvd menu" ); } - else - { - p_demux->info.i_update |= - INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; - p_demux->info.i_title = 0; - p_demux->info.i_seekpoint = 0; - } } + var_Create( p_demux, "dvdnav-angle", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); + var_Get( p_demux, "dvdnav-angle", &val ); + i_angle = val.i_int > 0 ? val.i_int : 1; + /* Update default_pts to a suitable value for dvdnav access */ var_Create( p_demux, "dvdnav-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); @@ -426,6 +406,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_GET_TITLE_INFO: ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); pi_int = (int*)va_arg( args, int* ); + *((int*)va_arg( args, int* )) = 0; /* Title offset */ + *((int*)va_arg( args, int* )) = 1; /* Chapter offset */ /* Duplicate title infos */ *pi_int = p_sys->i_title; @@ -732,73 +714,6 @@ static int Demux( demux_t *p_demux ) return 1; } -/***************************************************************************** - * ParseCL: parse command line. - * Titles start from 0 (menu), chapters and angles start from 1. - *****************************************************************************/ -static char *ParseCL( vlc_object_t *p_this, char *psz_name, vlc_bool_t b_force, - int *i_title, int *i_chapter, int *i_angle ) -{ - char *psz_parser, *psz_source, *psz_next; - - psz_source = strdup( psz_name ); - if( psz_source == NULL ) return NULL; - - *i_title = -1; - *i_chapter = 1; - *i_angle = 1; - - /* Start with the end, because you could have : - * dvdnav:/Volumes/my@toto/VIDEO_TS@1,1 - * (yes, this is kludgy). */ - for( psz_parser = psz_source + strlen(psz_source) - 1; - psz_parser >= psz_source && *psz_parser != '@'; - psz_parser-- ); - - if( psz_parser >= psz_source && *psz_parser == '@' ) - { - /* Found options */ - *psz_parser = '\0'; - ++psz_parser; - - *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 >= 0 ? *i_title : -1; - *i_chapter = *i_chapter > 0 ? *i_chapter : 1; - *i_angle = *i_angle > 0 ? *i_angle : 1; - - if( !*psz_source ) - { - free( psz_source ); - if( !b_force ) - { - return NULL; - } - psz_source = config_GetPsz( p_this, "dvd" ); - if( !psz_source ) return NULL; - } - -#ifdef WIN32 - if( psz_source[0] && psz_source[1] == ':' && - psz_source[2] == '\\' && psz_source[3] == '\0' ) - { - psz_source[2] = '\0'; - } -#endif - - return psz_source; -} - static void DemuxTitles( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; @@ -855,8 +770,6 @@ static void DemuxTitles( demux_t *p_demux ) for( j = 0; j < __MAX( i_chapters, 1 ); j++ ) { s = vlc_seekpoint_New(); - s->psz_name = malloc( strlen( _("Chapter %i") ) + 20 ); - sprintf( s->psz_name, _("Chapter %i"), j + 1 ); TAB_APPEND( t->i_seekpoint, t->seekpoint, s ); } diff --git a/modules/access/dvdread.c b/modules/access/dvdread.c index 43a5511116..a72f32da67 100644 --- a/modules/access/dvdread.c +++ b/modules/access/dvdread.c @@ -54,6 +54,10 @@ /***************************************************************************** * Module descriptor *****************************************************************************/ +#define ANGLE_TEXT N_("DVD angle") +#define ANGLE_LONGTEXT N_( \ + "Allows you to select the default DVD angle." ) + #define CACHING_TEXT N_("Caching value in ms") #define CACHING_LONGTEXT N_( \ "Allows you to modify the default caching value for DVDread streams. " \ @@ -84,13 +88,15 @@ static void Close( vlc_object_t * ); vlc_module_begin(); set_description( _("DVDRead Input") ); + add_integer( "dvdread-angle", 1, NULL, ANGLE_TEXT, + ANGLE_LONGTEXT, VLC_FALSE ); add_integer( "dvdread-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); add_string( "dvdread-css-method", NULL, NULL, CSSMETHOD_TEXT, CSSMETHOD_LONGTEXT, VLC_TRUE ); change_string_list( psz_css_list, psz_css_list_text, 0 ); set_capability( "access_demux", 0 ); - //add_shortcut( "dvd" ); + add_shortcut( "dvd" ); add_shortcut( "dvdread" ); add_shortcut( "dvdsimple" ); set_callbacks( Open, Close ); @@ -150,13 +156,11 @@ struct demux_sys_t uint32_t clut[16]; }; -static char *ParseCL( vlc_object_t *, char *, vlc_bool_t, int *, int *, int *); - static int Control ( demux_t *, int, va_list ); static int Demux ( demux_t * ); static int DemuxBlock( demux_t *, uint8_t *, int ); -static void DemuxTitles( demux_t *, int *, int *, int * ); +static void DemuxTitles( demux_t *, int * ); static void ESNew( demux_t *, int, int ); static int DvdReadSetArea ( demux_t *, int, int, int ); @@ -171,18 +175,30 @@ static int Open( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; - int i_title, i_chapter, i_angle; char *psz_name; char *psz_dvdcss_env; dvd_reader_t *p_dvdread; ifo_handle_t *p_vmg_file; + vlc_value_t val; - psz_name = ParseCL( VLC_OBJECT(p_demux), p_demux->psz_path, VLC_TRUE, - &i_title, &i_chapter, &i_angle ); - if( !psz_name ) + if( !p_demux->psz_path || !*p_demux->psz_path ) { - return VLC_EGENERIC; + /* Only when selected */ + if( !p_this->b_force ) return VLC_EGENERIC; + + psz_name = var_CreateGetString( p_this, "dvd" ); + if( !psz_name || !*psz_name ) + { + if( psz_name ) free( psz_name ); + return VLC_EGENERIC; + } } + else psz_name = strdup( p_demux->psz_path ); + +#ifdef WIN32 + if( psz_name[0] && psz_name[1] == ':' && + psz_name[2] == '\\' && psz_name[3] == '\0' ) psz_name[2] = '\0'; +#endif /* Override environment variable DVDCSS_METHOD with config option * (FIXME: this creates a small memory leak) */ @@ -193,7 +209,6 @@ static int Open( vlc_object_t *p_this ) psz_env = malloc( strlen("DVDCSS_METHOD=") + strlen( psz_dvdcss_env ) + 1 ); - if( !psz_env ) { free( psz_dvdcss_env ); @@ -239,11 +254,13 @@ static int Open( vlc_object_t *p_this ) p_sys->p_vts_file = NULL; p_sys->i_title = p_sys->i_chapter = -1; - p_sys->i_angle = i_angle; - DemuxTitles( p_demux, &i_title, &i_chapter, &i_angle ); + var_Create( p_demux, "dvdread-angle", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); + var_Get( p_demux, "dvdread-angle", &val ); + p_sys->i_angle = val.i_int > 0 ? val.i_int : 1; - DvdReadSetArea( p_demux, i_title, i_chapter, i_angle ); + DemuxTitles( p_demux, &p_sys->i_angle ); + DvdReadSetArea( p_demux, 0, 0, p_sys->i_angle ); /* Update default_pts to a suitable value for dvdread access */ var_Create( p_demux, "dvdread-caching", @@ -350,6 +367,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_GET_TITLE_INFO: ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); pi_int = (int*)va_arg( args, int* ); + *((int*)va_arg( args, int* )) = 1; /* Title offset */ + *((int*)va_arg( args, int* )) = 1; /* Chapter offset */ /* Duplicate title infos */ *pi_int = p_sys->i_titles; @@ -433,14 +452,18 @@ static int Demux( demux_t *p_demux ) /* End of title */ if( p_sys->i_next_vobu > p_sys->i_title_end_block ) { - if( p_sys->i_title + 1 >= p_sys->i_titles ) return 0; /* EOF */ + if( p_sys->i_title + 1 >= p_sys->i_titles ) + { + return 0; /* EOF */ + } DvdReadSetArea( p_demux, p_sys->i_title + 1, 0, -1 ); } if( p_sys->i_pack_len >= 1024 ) { - msg_Err( p_demux, "i_pack_len >= 1024. This shouldn't happen!" ); + msg_Err( p_demux, "i_pack_len >= 1024 (%i). " + "This shouldn't happen!", p_sys->i_pack_len ); return 0; /* EOF */ } @@ -454,7 +477,10 @@ static int Demux( demux_t *p_demux ) if( p_sys->i_cur_block > p_sys->i_title_end_block ) { - if( p_sys->i_title + 1 >= p_sys->i_titles ) return 0; /* EOF */ + if( p_sys->i_title + 1 >= p_sys->i_titles ) + { + return 0; /* EOF */ + } DvdReadSetArea( p_demux, p_sys->i_title + 1, 0, -1 ); } @@ -901,7 +927,7 @@ static int DvdReadSetArea( demux_t *p_demux, int i_title, int i_chapter, * Chapter selection */ - if( i_chapter >= 0 && i_chapter <= p_sys->i_chapters ) + if( i_chapter >= 0 && i_chapter < p_sys->i_chapters ) { pgc_id = p_vts->vts_ptt_srpt->title[ p_sys->i_ttn - 1].ptt[i_chapter].pgcn; @@ -1052,6 +1078,7 @@ static void DvdReadHandleDSI( demux_t *p_demux, uint8_t *p_data ) * care about. */ p_sys->i_cur_block = p_sys->dsi_pack.dsi_gi.nv_pck_lbn; + p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; /* * If we're not at the end of this cell, we can determine the next @@ -1060,7 +1087,12 @@ static void DvdReadHandleDSI( demux_t *p_demux, uint8_t *p_data ) * avoiding the doubled scenes in The Matrix, and makes our life * really happy. */ - if( p_sys->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL ) + + p_sys->i_next_vobu = p_sys->i_cur_block + + ( p_sys->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); + + if( p_sys->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL + && p_sys->i_angle > 1 ) { switch( ( p_sys->dsi_pack.sml_pbi.category & 0xf000 ) >> 12 ) { @@ -1076,7 +1108,6 @@ static void DvdReadHandleDSI( demux_t *p_demux, uint8_t *p_data ) { p_sys->i_next_vobu = p_sys->i_cur_block + p_sys->dsi_pack.dsi_gi.vobu_ea + 1; - p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; } break; case 0x5: @@ -1100,16 +1131,14 @@ static void DvdReadHandleDSI( demux_t *p_demux, uint8_t *p_data ) default: p_sys->i_next_vobu = p_sys->i_cur_block + ( p_sys->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); - p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; break; } } - else + else if( p_sys->dsi_pack.vobu_sri.next_vobu == SRI_END_OF_CELL ) { p_sys->i_cur_cell = p_sys->i_next_cell; DvdReadFindCell( p_demux ); - p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; p_sys->i_next_vobu = p_sys->p_cur_pgc->cell_playback[p_sys->i_cur_cell].first_sector; } @@ -1187,8 +1216,7 @@ static void DvdReadFindCell( demux_t *p_demux ) /***************************************************************************** * DemuxTitles: get the titles/chapters structure *****************************************************************************/ -static void DemuxTitles( demux_t *p_demux, - int *pi_title, int *pi_chapter, int *pi_angle ) +static void DemuxTitles( demux_t *p_demux, int *pi_angle ) { demux_sys_t *p_sys = p_demux->p_sys; input_title_t *t; @@ -1211,97 +1239,15 @@ static void DemuxTitles( demux_t *p_demux, msg_Dbg( p_demux, "title %d has %d chapters", i, i_chapters ); t = vlc_input_title_New(); - t->psz_name = malloc( strlen( _("Title %i") ) + 20 ); - sprintf( t->psz_name, _("Title %i"), i + 1 ); for( j = 0; j < __MAX( i_chapters, 1 ); j++ ) { s = vlc_seekpoint_New(); - s->psz_name = malloc( strlen( _("Chapter %i") ) + 20 ); - sprintf( s->psz_name, _("Chapter %i"), j + 1 ); TAB_APPEND( t->i_seekpoint, t->seekpoint, s ); } TAB_APPEND( p_sys->i_titles, p_sys->titles, t ); } - /* Set forced title/chapter/angle */ - *pi_title = (*pi_title >= 0 && *pi_title < i_titles) ? *pi_title : 0; - *pi_chapter = (*pi_chapter >= 0 && *pi_chapter < - tt_srpt->title[*pi_title].nr_of_ptts) ? *pi_chapter : 0; - #undef tt_srpt } - -/***************************************************************************** - * ParseCL: parse command line. Titles, chapters and angles start from 1. - *****************************************************************************/ -static char *ParseCL( vlc_object_t *p_this, char *psz_name, vlc_bool_t b_force, - int *i_title, int *i_chapter, int *i_angle ) -{ - char *psz_parser, *psz_source, *psz_next; - - psz_source = strdup( psz_name ); - if( psz_source == NULL ) return NULL; - - *i_title = 1; - *i_chapter = 1; - *i_angle = 1; - - /* Start with the end, because you could have : - * dvdnav:/Volumes/my@toto/VIDEO_TS@1,1 - * (yes, this is kludgy). */ - for( psz_parser = psz_source + strlen(psz_source) - 1; - psz_parser >= psz_source && *psz_parser != '@'; - psz_parser-- ); - - if( psz_parser >= psz_source && *psz_parser == '@' ) - { - /* Found options */ - *psz_parser = '\0'; - ++psz_parser; - - *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 > 0 ? *i_title : 1; - *i_chapter = *i_chapter > 0 ? *i_chapter : 1; - *i_angle = *i_angle > 0 ? *i_angle : 1; - - if( !*psz_source ) - { - free( psz_source ); - if( !b_force ) - { - return NULL; - } - psz_source = config_GetPsz( p_this, "dvd" ); - if( !psz_source ) return NULL; - } - -#ifdef WIN32 - if( psz_source[0] && psz_source[1] == ':' && - psz_source[2] == '\\' && psz_source[3] == '\0' ) - { - psz_source[2] = '\0'; - } -#endif - - msg_Dbg( p_this, "dvdroot=%s title=%d chapter=%d angle=%d", - psz_source, *i_title, *i_chapter, *i_angle ); - - /* Get back to a 0-based offset */ - (*i_title)--; - (*i_chapter)--; - - return psz_source; -} diff --git a/src/input/input.c b/src/input/input.c index e0a95e96a1..4af7554ae5 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -53,8 +53,8 @@ static void ControlReduce( input_thread_t * ); static vlc_bool_t Control( input_thread_t *, int, vlc_value_t ); -static void UpdateFromAccess( input_thread_t * ); -static void UpdateFromDemux( input_thread_t * ); +static int UpdateFromAccess( input_thread_t * ); +static int UpdateFromDemux( input_thread_t * ); static void UpdateItemLength( input_thread_t *, int64_t i_length ); @@ -62,6 +62,7 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option ); static void DecodeUrl ( char * ); static void MRLSplit( input_thread_t *, char *, char **, char **, char ** ); +static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *); static input_source_t *InputSourceNew( input_thread_t *); static int InputSourceInit( input_thread_t *, input_source_t *, @@ -123,6 +124,7 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, p_input->i_stop = 0; p_input->i_title = 0; p_input->title = NULL; + p_input->i_title_offset = p_input->i_seekpoint_offset = 0; p_input->i_state = INIT_S; p_input->i_rate = INPUT_RATE_DEFAULT; p_input->i_bookmark = 0; @@ -132,7 +134,6 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, p_input->b_out_pace_control = VLC_FALSE; p_input->i_pts_delay = 0; - /* Init Input fields */ p_input->input.p_item = p_item; p_input->input.p_access = NULL; @@ -141,6 +142,7 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent, p_input->input.b_title_demux = VLC_FALSE; p_input->input.i_title = 0; p_input->input.title = NULL; + p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0; p_input->input.b_can_pace_control = VLC_TRUE; p_input->input.b_eof = VLC_FALSE; p_input->input.i_cr_average = 0; @@ -344,18 +346,19 @@ static int Run( input_thread_t *p_input ) if( p_input->input.b_title_demux && p_input->input.p_demux->info.i_update ) { - UpdateFromDemux( p_input ); + i_ret = UpdateFromDemux( p_input ); b_force_update = VLC_TRUE; } else if( !p_input->input.b_title_demux && p_input->input.p_access && p_input->input.p_access->info.i_update ) { - UpdateFromAccess( p_input ); + i_ret = UpdateFromAccess( p_input ); b_force_update = VLC_TRUE; } } - else if( i_ret == 0 ) /* EOF */ + + if( i_ret == 0 ) /* EOF */ { vlc_value_t repeat; @@ -377,9 +380,21 @@ static int Run( input_thread_t *p_input ) var_Set( p_input, "input-repeat", repeat ); } - /* Seek to title 0 position 0(start) */ - val.i_int = 0; - input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val ); + /* Seek to start title/seekpoint */ + val.i_int = p_input->input.i_title_start - + p_input->input.i_title_offset; + if( val.i_int < 0 || val.i_int >= p_input->input.i_title ) + val.i_int = 0; + input_ControlPush( p_input, + INPUT_CONTROL_SET_TITLE, &val ); + + val.i_int = p_input->input.i_seekpoint_start - + p_input->input.i_seekpoint_offset; + if( val.i_int > 0 /* TODO: check upper boundary */ ) + input_ControlPush( p_input, + INPUT_CONTROL_SET_SEEKPOINT, &val ); + + /* Seek to start position */ if( p_input->i_start > 0 ) { val.i_time = p_input->i_start; @@ -421,8 +436,7 @@ static int Run( input_thread_t *p_input ) } vlc_mutex_unlock( &p_input->lock_control ); - if( b_force_update || - i_intf_update < mdate() ) + if( b_force_update || i_intf_update < mdate() ) { vlc_value_t val; double f_pos; @@ -529,6 +543,8 @@ static int Init( input_thread_t * p_input ) /* Create global title (from master) */ p_input->i_title = p_input->input.i_title; p_input->title = p_input->input.title; + p_input->i_title_offset = p_input->input.i_title_offset; + p_input->i_seekpoint_offset = p_input->input.i_seekpoint_offset; if( p_input->i_title > 0 ) { /* Setup variables */ @@ -547,8 +563,7 @@ static int Init( input_thread_t * p_input ) /* If the desynchronisation requested by the user is < 0, we need to * cache more data. */ var_Get( p_input, "audio-desync", &val ); - if( val.i_int < 0 ) - p_input->i_pts_delay -= (val.i_int * 1000); + if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000); /* Load master infos */ /* Init length */ @@ -559,6 +574,17 @@ static int Init( input_thread_t * p_input ) UpdateItemLength( p_input, val.i_time ); } + + /* Start title/chapter */ + val.i_int = p_input->input.i_title_start - + p_input->input.i_title_offset; + if( val.i_int > 0 && val.i_int < p_input->input.i_title ) + input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val ); + val.i_int = p_input->input.i_seekpoint_start - + p_input->input.i_seekpoint_offset; + if( val.i_int > 0 /* TODO: check upper boundary */ ) + input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val ); + /* Start time*/ /* Set start time */ p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) * @@ -1344,7 +1370,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, /***************************************************************************** * UpdateFromDemux: *****************************************************************************/ -static void UpdateFromDemux( input_thread_t *p_input ) +static int UpdateFromDemux( input_thread_t *p_input ) { demux_t *p_demux = p_input->input.p_demux; vlc_value_t v; @@ -1366,12 +1392,38 @@ static void UpdateFromDemux( input_thread_t *p_input ) p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT; } p_demux->info.i_update &= ~INPUT_UPDATE_SIZE; + + /* Hmmm only works with master input */ + if( p_input->input.p_demux == p_demux ) + { + int i_title_end = p_input->input.i_title_end - + p_input->input.i_title_offset; + int i_seekpoint_end = p_input->input.i_seekpoint_end - + p_input->input.i_seekpoint_offset; + + if( i_title_end >= 0 && i_seekpoint_end >=0 ) + { + if( p_demux->info.i_title > i_title_end || + ( p_demux->info.i_title == i_title_end && + p_demux->info.i_seekpoint > i_seekpoint_end ) ) return 0; + } + else if( i_seekpoint_end >=0 ) + { + if( p_demux->info.i_seekpoint > i_seekpoint_end ) return 0; + } + else if( i_title_end >= 0 ) + { + if( p_demux->info.i_title > i_title_end ) return 0; + } + } + + return 1; } /***************************************************************************** * UpdateFromAccess: *****************************************************************************/ -static void UpdateFromAccess( input_thread_t *p_input ) +static int UpdateFromAccess( input_thread_t *p_input ) { access_t *p_access = p_input->input.p_access; vlc_value_t v; @@ -1395,6 +1447,32 @@ static void UpdateFromAccess( input_thread_t *p_input ) p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT; } p_access->info.i_update &= ~INPUT_UPDATE_SIZE; + + /* Hmmm only works with master input */ + if( p_input->input.p_access == p_access ) + { + int i_title_end = p_input->input.i_title_end - + p_input->input.i_title_offset; + int i_seekpoint_end = p_input->input.i_seekpoint_end - + p_input->input.i_seekpoint_offset; + + if( i_title_end >= 0 && i_seekpoint_end >=0 ) + { + if( p_access->info.i_title > i_title_end || + ( p_access->info.i_title == i_title_end && + p_access->info.i_seekpoint > i_seekpoint_end ) ) return 0; + } + else if( i_seekpoint_end >=0 ) + { + if( p_access->info.i_seekpoint > i_seekpoint_end ) return 0; + } + else if( i_title_end >= 0 ) + { + if( p_access->info.i_title > i_title_end ) return 0; + } + } + + return 1; } /***************************************************************************** @@ -1452,6 +1530,10 @@ static int InputSourceInit( input_thread_t *p_input, msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'", psz_mrl, psz_access, psz_demux, psz_path ); + /* Find optional titles and seekpoints */ + MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end, + &in->i_seekpoint_start, &in->i_seekpoint_end ); + if( psz_forced_demux && *psz_forced_demux ) psz_demux = psz_forced_demux; @@ -1472,9 +1554,9 @@ static int InputSourceInit( input_thread_t *p_input, p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay ); in->b_title_demux = VLC_TRUE; - if( demux2_Control( in->p_demux, - DEMUX_GET_TITLE_INFO, - &in->title, &in->i_title ) ) + if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO, + &in->title, &in->i_title, + &in->i_title_offset, &in->i_seekpoint_offset ) ) { in->i_title = 0; in->title = NULL; @@ -1537,9 +1619,10 @@ static int InputSourceInit( input_thread_t *p_input, p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay ); in->b_title_demux = VLC_FALSE; - if( access2_Control( in->p_access, - ACCESS_GET_TITLE_INFO, - &in->title, &in->i_title ) ) + if( access2_Control( in->p_access, ACCESS_GET_TITLE_INFO, + &in->title, &in->i_title, + &in->i_title_offset, &in->i_seekpoint_offset ) ) + { in->i_title = 0; in->title = NULL; @@ -1578,7 +1661,8 @@ static int InputSourceInit( input_thread_t *p_input, if( in->i_title <= 0 ) { if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO, - &in->title, &in->i_title ) ) + &in->title, &in->i_title, + &in->i_title_offset, &in->i_seekpoint_offset )) { in->i_title = 0; in->title = NULL; @@ -1871,6 +1955,10 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option ) return; } +/***************************************************************************** + * MRLSplit: parse the access, demux and url part of the + * Media Resource Locator. + *****************************************************************************/ static void MRLSplit( input_thread_t *p_input, char *psz_dup, char **ppsz_access, char **ppsz_demux, char **ppsz_path ) { @@ -1928,3 +2016,56 @@ static void MRLSplit( input_thread_t *p_input, char *psz_dup, else *ppsz_path = psz_path; } + +/***************************************************************************** + * MRLSections: parse title and seekpoint info from the Media Resource Locator. + * + * Syntax: + * [url][@[title-start][,chapter-start][-[title-end][,chapter-end]]] + *****************************************************************************/ +static void MRLSections( input_thread_t *p_input, char *psz_source, + int *pi_title_start, int *pi_title_end, + int *pi_chapter_start, int *pi_chapter_end ) +{ + char *psz, *psz_end, *psz_next; + + *pi_title_start = *pi_title_end = -1; + *pi_chapter_start = *pi_chapter_end = -1; + + /* Start by parsing titles and chapters */ + if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return; + + *psz++ = 0; + + /* Separate start and end */ + if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0; + + /* Look for the start title */ + *pi_title_start = strtol( psz, &psz_next, 0 ); + if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1; + *pi_title_end = *pi_title_start; + psz = psz_next; + + /* Look for the start chapter */ + if( *psz ) psz++; + *pi_chapter_start = strtol( psz, &psz_next, 0 ); + if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1; + *pi_chapter_end = *pi_chapter_start; + + if( psz_end ) + { + /* Look for the end title */ + *pi_title_end = strtol( psz_end, &psz_next, 0 ); + if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1; + psz_end = psz_next; + + /* Look for the end chapter */ + if( *psz_end ) psz_end++; + *pi_chapter_end = strtol( psz_end, &psz_next, 0 ); + if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1; + } + + msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d", + psz_source, *pi_title_start, *pi_chapter_start, + *pi_title_end, *pi_chapter_end ); +} diff --git a/src/input/var.c b/src/input/var.c index e406a82fde..c75933b7c5 100644 --- a/src/input/var.c +++ b/src/input/var.c @@ -281,8 +281,8 @@ void input_ControlVarNavigation( input_thread_t *p_input ) if( p_input->title[i]->psz_name == NULL || *p_input->title[i]->psz_name == '\0' ) { - text.psz_string = malloc( strlen( _("Title %i") ) + 20 ); - sprintf( text.psz_string, _("Title %i"), i ); + asprintf( &text.psz_string, _("Title %i"), + i + p_input->i_title_offset ); } else { @@ -304,8 +304,8 @@ void input_ControlVarNavigation( input_thread_t *p_input ) *p_input->title[i]->seekpoint[j]->psz_name == '\0' ) { /* Default value */ - text2.psz_string = malloc( strlen( _("Chapter %i") ) + 20 ); - sprintf( text2.psz_string, _("Chapter %i"), j ); + asprintf( &text2.psz_string, _("Chapter %i"), + j + p_input->i_seekpoint_offset ); } else { @@ -364,8 +364,8 @@ void input_ControlVarTitle( input_thread_t *p_input, int i_title ) *t->seekpoint[i]->psz_name == '\0' ) { /* Default value */ - text.psz_string = malloc( strlen( _("Chapter %i") ) + 20 ); - sprintf( text.psz_string, _("Chapter %i"), i ); + asprintf( &text.psz_string, _("Chapter %i"), + i + p_input->i_seekpoint_offset ); } else {