+/*****************************************************************************
+ * AccessDemuxOpen:
+ *****************************************************************************/
+static int AccessDemuxOpen ( vlc_object_t *p_this )
+{
+ demux_t *p_demux = (demux_t*)p_this;
+ dvdnav_t *p_dvdnav = NULL;
+ char *psz_file = NULL;
+ const char *psz_path = NULL;
+ int i_ret = VLC_EGENERIC;
+ 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 )
+ goto bailout;
+
+ /* Open dvdnav */
+ psz_path = ToLocale( psz_file );
+ if( dvdnav_open( &p_dvdnav, psz_path ) != DVDNAV_STATUS_OK )
+ {
+ msg_Warn( p_demux, "cannot open DVD (%s)", psz_file);
+ goto bailout;
+ }
+
+ i_ret = CommonOpen( p_this, p_dvdnav, !!DVD_READ_CACHE );
+ if( i_ret != VLC_SUCCESS )
+ dvdnav_close( p_dvdnav );
+
+bailout:
+ free( psz_file );
+ if( psz_path )
+ LocaleFree( psz_path );
+ return i_ret;
+}
+
+#ifdef HAVE_DVDNAV_DEMUX
+/*****************************************************************************
+ * 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;
+}
+
+/*****************************************************************************
+ * 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;
+ dvdnav_t *p_dvdnav = NULL;
+ 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,
+ };
+
+ /* Open dvdnav with stream callbacks */
+ if( dvdnav_open_stream( &p_dvdnav, p_demux->s,
+ &stream_cb ) != DVDNAV_STATUS_OK )
+ {
+ msg_Warn( p_demux, "cannot open DVD with open_stream" );
+ goto bailout;
+ }
+
+ i_ret = CommonOpen( p_this, p_dvdnav, false );
+ if( i_ret != VLC_SUCCESS )
+ dvdnav_close( p_dvdnav );
+
+bailout:
+ if( i_ret != VLC_SUCCESS )
+ stream_Seek( p_demux->s, i_init_pos );
+ return i_ret;
+}
+#endif
+