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

Thomas Guillem thomas at gllm.fr
Mon Mar 23 19:48:27 CET 2015


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;
+
+    /* 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;
+}
-- 
2.1.3




More information about the vlc-devel mailing list