[vlc-devel] [PATCH] dvdnav: add Demux submodule

Thomas Guillem thomas at gllm.fr
Tue Mar 24 11:51:32 CET 2015


Some changes in DemuxOpen and StreamProbeDVD : 
 - Don't seek back if probe succeed.
 - If CommonOpen fails, seek back to the initial position.

On Tue, Mar 24, 2015, at 11:49, 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 | 230
>  ++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 174 insertions(+), 56 deletions(-)
> 
> diff --git a/modules/access/dvdnav.c b/modules/access/dvdnav.c
> index ad1240a..fde57e1 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( !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( unlikely( psz_file == NULL &&
> +        ( p_dvd_stream == NULL || p_dvd_stream_cb == NULL ) ) )
> +        return VLC_EGENERIC;
>  
> -#if defined( _WIN32 ) || defined( __OS2__ )
> -    if( psz_file != NULL )
> +    if( p_dvd_stream != 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';
> +        /* 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("");
> -#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,112 @@ 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;
> +    int i_ret;
> +    int64_t i_init_pos;
> +    bool forced = false, b_seekable = false;
> +
> +    if( p_demux->psz_demux != NULL
> +     && !strncmp(p_demux->psz_demux, "dvd", 3) )
> +        forced = true;
> +
> +    /* StreamProbeDVD need FASTSEEK, but if dvd is forced, we don't
> probe thus
> +     * don't need fastseek */
> +    stream_Control( p_demux->s, forced ? STREAM_CAN_SEEK :
> STREAM_CAN_FASTSEEK,
> +                    &b_seekable );
> +    if( !b_seekable )
> +        return VLC_EGENERIC;
> +
> +    i_init_pos = stream_Tell( p_demux->s );
> +
> +    /* Try some simple probing to avoid going through dvdnav_open too
> often */
> +    if( !forced && (i_ret = StreamProbeDVD( p_demux->s )) != VLC_SUCCESS
> )
> +        goto bailout;
> +
> +    static dvdnav_stream_cb stream_cb =
> +    {
> +        .pf_seek = stream_cb_seek,
> +        .pf_read = stream_cb_read,
> +        .pf_readv = NULL,
> +    };
> +
> +    i_ret = CommonOpen( p_this, NULL, p_demux->s, &stream_cb );
> +bailout:
> +    if( i_ret != VLC_SUCCESS )
> +        stream_Seek( p_demux->s, i_init_pos );
> +    return i_ret;
> +}
> +
> +/*****************************************************************************
>   * Close:
>   *****************************************************************************/
>  static void Close( vlc_object_t *p_this )
> @@ -636,14 +732,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 +999,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 +1041,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 +1577,26 @@ bailout:
>      close( fd );
>      return ret;
>  }
> +
> +/*****************************************************************************
> + * StreamProbeDVD: very weak probing that avoids going too often into a
> dvdnav_open()
> +
> *****************************************************************************/
> +static int StreamProbeDVD( stream_t *s )
> +{
> +    /* ISO 9660 volume descriptor */
> +    char iso_dsc[6];
> +    if( stream_Seek( s, 0x8000 + 1 ) != VLC_SUCCESS
> +     || stream_Read( s, iso_dsc, sizeof (iso_dsc) ) < (int)sizeof
> (iso_dsc)
> +     || memcmp( iso_dsc, "CD001\x01", 6 ) )
> +        return VLC_EGENERIC;
> +
> +    /* Try to find the anchor (2 bytes at LBA 256) */
> +    uint16_t anchor;
> +
> +    if( stream_Seek( s, 256 * DVD_VIDEO_LB_LEN ) == VLC_SUCCESS
> +     && stream_Read( s, &anchor, 2 ) == 2
> +     && GetWLE( &anchor ) == 2 )
> +        return VLC_SUCCESS;
> +    else
> +        return VLC_EGENERIC;
> +}
> -- 
> 2.1.3
> 



More information about the vlc-devel mailing list