[vlc-devel] [PATCH] dvdnav: add Demux submodule
Petri Hintukainen
phintuka at users.sourceforge.net
Tue Mar 24 10:06:45 CET 2015
On ma, 2015-03-23 at 19:48 +0100, Thomas Guillem wrote:
> It allows to use dvdnav via a VLC access.
>
> When using a VLC access, dvdnav readahead flag is disabled in order to read
> small chunk of data from pf_demux (that is 2kB).
> ---
> modules/access/dvdnav.c | 220 ++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 164 insertions(+), 56 deletions(-)
>
> diff --git a/modules/access/dvdnav.c b/modules/access/dvdnav.c
> index ad1240a..c50ea34 100644
> --- a/modules/access/dvdnav.c
> +++ b/modules/access/dvdnav.c
> @@ -76,7 +76,8 @@
>
> #define LANGUAGE_DEFAULT ("en")
>
> -static int Open ( vlc_object_t * );
> +static int AccessDemuxOpen ( vlc_object_t * );
> +static int DemuxOpen ( vlc_object_t * );
> static void Close( vlc_object_t * );
>
> vlc_module_begin ()
> @@ -90,7 +91,14 @@ vlc_module_begin ()
> MENU_TEXT, MENU_LONGTEXT, false )
> set_capability( "access_demux", 5 )
> add_shortcut( "dvd", "dvdnav", "file" )
> - set_callbacks( Open, Close )
> + set_callbacks( AccessDemuxOpen, Close )
> + add_submodule()
> + set_description( N_("DVDnav demuxer") )
> + set_category( CAT_INPUT )
> + set_subcategory( SUBCAT_INPUT_DEMUX )
> + set_capability( "demux", 5 )
> + set_callbacks( DemuxOpen, Close )
> + add_shortcut( "dvd", "iso" )
> vlc_module_end ()
>
> /* Shall we use libdvdnav's read ahead cache? */
> @@ -109,6 +117,7 @@ struct demux_sys_t
>
> /* */
> bool b_reset_pcr;
> + bool b_readahead;
>
> struct
> {
> @@ -160,6 +169,7 @@ static void ButtonUpdate( demux_t *, bool );
>
> static void ESNew( demux_t *, int );
> static int ProbeDVD( const char * );
> +static int StreamProbeDVD( stream_t * );
>
> static char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var );
>
> @@ -173,66 +183,43 @@ static int EventIntf( vlc_object_t *, char const *,
> vlc_value_t, vlc_value_t, void * );
>
> /*****************************************************************************
> - * DemuxOpen:
> + * CommonOpen:
> *****************************************************************************/
> -static int Open( vlc_object_t *p_this )
> +static int CommonOpen( vlc_object_t *p_this, const char *psz_file,
> + void *p_dvd_stream,
> + dvdnav_stream_cb *p_dvd_stream_cb )
> {
> demux_t *p_demux = (demux_t*)p_this;
> demux_sys_t *p_sys;
> dvdnav_t *p_dvdnav;
> int i_angle;
> - char *psz_file;
> char *psz_code;
> - bool forced = false;
>
> - if( p_demux->psz_access != NULL
> - && !strncmp(p_demux->psz_access, "dvd", 3) )
> - forced = true;
> + if( unlikely( psz_file == NULL &&
> + ( p_dvd_stream == NULL || p_dvd_stream_cb == NULL ) ) )
> + return VLC_EGENERIC;
>
> - if( !p_demux->psz_file || !*p_demux->psz_file )
> + if( p_dvd_stream != NULL )
> {
> - /* Only when selected */
> - if( !forced )
> - return VLC_EGENERIC;
> -
> - psz_file = var_InheritString( p_this, "dvd" );
> + /* Open dvdnav with stream callbacks */
> + if( dvdnav_open_stream( &p_dvdnav, p_dvd_stream,
> + p_dvd_stream_cb ) != DVDNAV_STATUS_OK )
> + p_dvdnav = NULL;
> }
> else
> - psz_file = strdup( p_demux->psz_file );
> -
> -#if defined( _WIN32 ) || defined( __OS2__ )
> - if( psz_file != NULL )
> {
> - /* Remove trailing backslash, otherwise dvdnav_open will fail */
> - size_t flen = strlen( psz_file );
> - if( flen > 0 && psz_file[flen - 1] == '\\' )
> - psz_file[flen - 1] = '\0';
> - }
> - else
> - psz_file = strdup("");
> -#endif
> - if( unlikely(psz_file == NULL) )
> - return VLC_EGENERIC;
> -
> - /* Try some simple probing to avoid going through dvdnav_open too often */
> - if( !forced && ProbeDVD( psz_file ) != VLC_SUCCESS )
> - {
> - free( psz_file );
> - return VLC_EGENERIC;
> + /* Open dvdnav */
> + const char *psz_path = ToLocale( psz_file );
> + if( dvdnav_open( &p_dvdnav, psz_path ) != DVDNAV_STATUS_OK )
> + p_dvdnav = NULL;
> + LocaleFree( psz_path );
> }
>
> - /* Open dvdnav */
> - const char *psz_path = ToLocale( psz_file );
> - if( dvdnav_open( &p_dvdnav, psz_path ) != DVDNAV_STATUS_OK )
> - p_dvdnav = NULL;
> - LocaleFree( psz_path );
> if( p_dvdnav == NULL )
> {
> msg_Warn( p_demux, "cannot open DVD (%s)", psz_file);
> - free( psz_file );
> return VLC_EGENERIC;
> }
> - free( psz_file );
>
> /* Fill p_demux field */
> DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
> @@ -247,6 +234,9 @@ static int Open( vlc_object_t *p_this )
> p_sys->b_spu_change = false;
> p_sys->i_vobu_index = 0;
> p_sys->i_vobu_flush = 0;
> +#if DVD_READ_CACHE
> + p_sys->b_readahead = p_dvd_stream == NULL;
> +#endif
>
> if( 1 )
> {
> @@ -266,7 +256,7 @@ static int Open( vlc_object_t *p_this )
> }
>
> /* Configure dvdnav */
> - if( dvdnav_set_readahead_flag( p_sys->dvdnav, DVD_READ_CACHE ) !=
> + if( dvdnav_set_readahead_flag( p_sys->dvdnav, p_sys->b_readahead ) !=
> DVDNAV_STATUS_OK )
> {
> msg_Warn( p_demux, "cannot set read-a-head flag" );
> @@ -370,6 +360,101 @@ static int Open( vlc_object_t *p_this )
> }
>
> /*****************************************************************************
> + * AccessDemuxOpen:
> + *****************************************************************************/
> +static int AccessDemuxOpen ( vlc_object_t *p_this )
> +{
> + demux_t *p_demux = (demux_t*)p_this;
> + char *psz_file;
> + int i_ret;
> + bool forced = false;
> +
> + if( p_demux->psz_access != NULL
> + && !strncmp(p_demux->psz_access, "dvd", 3) )
> + forced = true;
> +
> + if( !p_demux->psz_file || !*p_demux->psz_file )
> + {
> + /* Only when selected */
> + if( !forced )
> + return VLC_EGENERIC;
> +
> + psz_file = var_InheritString( p_this, "dvd" );
> + }
> + else
> + psz_file = strdup( p_demux->psz_file );
> +
> +#if defined( _WIN32 ) || defined( __OS2__ )
> + if( psz_file != NULL )
> + {
> + /* Remove trailing backslash, otherwise dvdnav_open will fail */
> + size_t flen = strlen( psz_file );
> + if( flen > 0 && psz_file[flen - 1] == '\\' )
> + psz_file[flen - 1] = '\0';
> + }
> + else
> + psz_file = strdup("");
> +#endif
> +
> + if( unlikely(psz_file == NULL) )
> + return VLC_EGENERIC;
> +
> + /* Try some simple probing to avoid going through dvdnav_open too often */
> + if( !forced && ProbeDVD( psz_file ) != VLC_SUCCESS )
> + {
> + free( psz_file );
> + return VLC_EGENERIC;
> + }
> +
> + i_ret = CommonOpen( p_this, psz_file, NULL, NULL );
> + free( psz_file );
> + return i_ret;
> +}
> +
> +/*****************************************************************************
> + * dvdnav stream callbacks
> + *****************************************************************************/
> +static int stream_cb_seek( void *s, uint64_t pos )
> +{
> + return stream_Seek( (stream_t *)s, pos );
> +}
> +
> +static int stream_cb_read( void *s, void* buffer, int size )
> +{
> + return stream_Read( (stream_t *)s, buffer, size );
> +}
> +
> +/*****************************************************************************
> + * DemuxOpen:
> + *****************************************************************************/
> +static int DemuxOpen ( vlc_object_t *p_this )
> +{
> + demux_t *p_demux = (demux_t*)p_this;
> + bool forced = false, b_seekable = false;
> +
> + stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable );
> + if( !b_seekable )
> + return VLC_EGENERIC;
> +
> + if( p_demux->psz_demux != NULL
> + && !strncmp(p_demux->psz_demux, "dvd", 3) )
> + forced = true;
> +
> + static dvdnav_stream_cb stream_cb =
> + {
> + .pf_seek = stream_cb_seek,
> + .pf_read = stream_cb_read,
> + .pf_readv = NULL,
> + };
> +
> + /* Try some simple probing to avoid going through dvdnav_open too often */
> + if( !forced && StreamProbeDVD( p_demux->s ) != VLC_SUCCESS )
> + return VLC_EGENERIC;
> +
> + return CommonOpen( p_this, NULL, p_demux->s, &stream_cb );
> +}
> +
> +/*****************************************************************************
> * Close:
> *****************************************************************************/
> static void Close( vlc_object_t *p_this )
> @@ -636,14 +721,15 @@ static int Demux( demux_t *p_demux )
> uint8_t *packet = buffer;
> int i_event;
> int i_len;
> + dvdnav_status_t status;
>
> -#if DVD_READ_CACHE
> - if( dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event, &i_len )
> - == DVDNAV_STATUS_ERR )
> -#else
> - if( dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event, &i_len )
> - == DVDNAV_STATUS_ERR )
> -#endif
> + if( p_sys->b_readahead )
> + status = dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event,
> + &i_len );
> + else
> + status = dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event,
> + &i_len );
> + if( status == DVDNAV_STATUS_ERR )
> {
> msg_Warn( p_demux, "cannot get next block (%s)",
> dvdnav_err_to_string( p_sys->dvdnav ) );
> @@ -902,9 +988,8 @@ static int Demux( demux_t *p_demux )
> case DVDNAV_STOP: /* EOF */
> msg_Dbg( p_demux, "DVDNAV_STOP" );
>
> -#if DVD_READ_CACHE
> - dvdnav_free_cache_block( p_sys->dvdnav, packet );
> -#endif
> + if( p_sys->b_readahead )
> + dvdnav_free_cache_block( p_sys->dvdnav, packet );
> return 0;
>
> case DVDNAV_HIGHLIGHT:
> @@ -945,9 +1030,8 @@ static int Demux( demux_t *p_demux )
> break;
> }
>
> -#if DVD_READ_CACHE
> - dvdnav_free_cache_block( p_sys->dvdnav, packet );
> -#endif
> + if( p_sys->b_readahead )
> + dvdnav_free_cache_block( p_sys->dvdnav, packet );
>
> return 1;
> }
> @@ -1482,3 +1566,27 @@ bailout:
> close( fd );
> return ret;
> }
> +
> +/*****************************************************************************
> + * StreamProbeDVD: very weak probing that avoids going too often into a dvdnav_open()
> + *****************************************************************************/
> +static int StreamProbeDVD( stream_t *s )
> +{
> + uint16_t anchor;
> + const uint8_t *p_peek;
> + int i_peek = 256 * DVD_VIDEO_LB_LEN + sizeof(anchor);
> +
> + if( stream_Peek( s, &p_peek, i_peek ) < i_peek )
> + return VLC_EGENERIC;
Would it make any sense to do multiple peeks ?
Maybe check first if the file starts with sequence of 0 bytes (I'm not
sure if this would work with all DVDs ...)
Then, peek first 32kb for the first check, and finally 512kb for the
second ?
That could make (failing) probe faster with slow access ?
> +
> + /* ISO 9660 volume descriptor */
> + if( memcmp( p_peek + 0x8000 + 1, "CD001\x01", 6 ) )
> + return VLC_EGENERIC;
> + /* Try to find the anchor (2 bytes at LBA 256) */
> + anchor = *(uint16_t *)( p_peek + 256 * DVD_VIDEO_LB_LEN );
> + if( GetWLE( &anchor ) == 2 )
> + return VLC_SUCCESS; /* Found a potential anchor */
> + else
> + return VLC_EGENERIC;
> +}
More information about the vlc-devel
mailing list