-Patch of libdvdread to do readv on regular files (dvd copied on hard drive).
authorStéphane Borel <stef@videolan.org>
Tue, 15 Jan 2002 05:22:21 +0000 (05:22 +0000)
committerStéphane Borel <stef@videolan.org>
Tue, 15 Jan 2002 05:22:21 +0000 (05:22 +0000)
Not completed, and little tested yet ; when it is completed, this patch should
be submitted to libdvdread developers.

-Patch of libdvdcss to decrypt vobs when they are not on a block device.

extras/libdvdcss/libdvdcss.c
extras/libdvdread/dvdread.c
extras/libdvdread/videolan/dvdread.c

index 638fb8c..bcf1434 100644 (file)
@@ -2,7 +2,7 @@
  * libdvdcss.c: DVD reading library.
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: libdvdcss.c,v 1.27 2002/01/14 22:06:57 stef Exp $
+ * $Id: libdvdcss.c,v 1.28 2002/01/15 05:22:21 stef Exp $
  *
  * Authors: Stéphane Borel <stef@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -79,7 +79,8 @@ static int _dvdcss_raw_open     ( dvdcss_handle, char *psz_target );
  *****************************************************************************/
 extern dvdcss_handle dvdcss_open ( char *psz_target )
 {
-    int i_ret;
+    struct stat fileinfo;
+    int         i_ret;
 
     char *psz_method = getenv( "DVDCSS_METHOD" );
     char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
@@ -157,18 +158,35 @@ extern dvdcss_handle dvdcss_open ( char *psz_target )
         return NULL;
     }
 
-    i_ret = CSSTest( dvdcss );
-    if( i_ret < 0 )
+    if( stat( psz_target, &fileinfo ) < 0 )
     {
-        _dvdcss_error( dvdcss, "CSS test failed" );
-        /* Disable the CSS ioctls and hope that it works? */
-        dvdcss->b_ioctls = 0;
-        dvdcss->b_encrypted = 1;
+        _dvdcss_error( dvdcss, "dvdcss: can't stat target" );
+    }
+    
+    if( S_ISBLK( fileinfo.st_mode ) || 
+        S_ISCHR( fileinfo.st_mode ) )
+    {        
+        i_ret = CSSTest( dvdcss );
+        if( i_ret < 0 )
+        {
+            _dvdcss_error( dvdcss, "CSS test failed" );
+            /* Disable the CSS ioctls and hope that it works? */
+            dvdcss->b_ioctls = 0;
+            dvdcss->b_encrypted = 1;
+        }
+        else
+        {
+            dvdcss->b_ioctls = 1;
+            dvdcss->b_encrypted = i_ret;
+        }
     }
     else
     {
-        dvdcss->b_ioctls = 1;
-        dvdcss->b_encrypted = i_ret;
+        _dvdcss_debug( dvdcss, "dvdcss: file mode, using title method" );
+        dvdcss->i_method = DVDCSS_METHOD_TITLE;
+        dvdcss->b_ioctls = 0;
+        dvdcss->b_encrypted = 1;
+        memset( &dvdcss->css.disc, 0, sizeof(dvdcss->css.disc) );
     }
 
     /* If disc is CSS protected and the ioctls work, authenticate the drive */
@@ -182,10 +200,10 @@ extern dvdcss_handle dvdcss_open ( char *psz_target )
             free( dvdcss );
             return NULL;
         }
+        
+        memset( dvdcss->css.p_unenc_key, 0, KEY_SIZE );
     }
 
-    memset( dvdcss->css.p_unenc_key, 0, KEY_SIZE );
-
 #ifndef WIN32
     if( psz_raw_device != NULL )
     {
@@ -211,7 +229,8 @@ extern int dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks, int i_flags )
 {
     /* title cracking method is too slow to be used at each seek */
     if( ( ( i_flags & DVDCSS_SEEK_MPEG )
-             && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) ) )
+             && ( dvdcss->i_method != DVDCSS_METHOD_TITLE ) )
+             && dvdcss->b_encrypted )
     {
         int     i_ret;
 
index 50b83c2..bef6458 100644 (file)
@@ -3,7 +3,7 @@
  * (hard-linked) and adds a readv call function to tha API.
  *****************************************************************************
  * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
- * $Id: dvdread.c,v 1.2 2001/11/26 22:28:05 fgp Exp $
+ * $Id: dvdread.c,v 1.3 2002/01/15 05:22:21 stef Exp $
  *
  * Author: Billy Biggs <vektor@dumbterm.net>
  *         Stéphane Borel <stef@via.ecp.fr>
 #include <string.h>
 #include <unistd.h>
 #include <limits.h>
+#include <dlfcn.h>
 #include <dirent.h>
 
 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)
 #define SYS_BSD 1
 #endif
 
-#ifdef SYS_DARWIN
-#define off64_t off_t
-#define stat64 stat
-#define lseek64 lseek
-#endif
-
 #if defined(__sun)
 #include <sys/mnttab.h>
 #elif defined(SYS_BSD)
@@ -86,6 +81,7 @@ struct dvd_file_s {
     uint32_t seek_pos;
 
     /* Information required for a directory path drive. */
+    dvdcss_handle title_devs[9];
     size_t title_sizes[ 9 ];
     int title_fds[ 9 ];
 
@@ -124,6 +120,7 @@ static dvd_reader_t *DVDOpenPath( const char *path_root )
 {
     dvd_reader_t *dvd;
 
+    fprintf(stderr, "libdvdread: opening %s as folder\n", path_root );
     dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
     if( !dvd ) return 0;
     dvd->isImageFile = 0;
@@ -353,11 +350,13 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
     start = UDFFindFile( dvd, filename, &len );
     if( !start ) return 0;
 
+    fprintf( stderr, "libdvdread: opening %s as image\n", filename );
     dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
     if( !dvd_file ) return 0;
     dvd_file->dvd = dvd;
     dvd_file->lb_start = start;
     dvd_file->seek_pos = 0;
+    memset( dvd_file->title_devs, -1, sizeof( dvd_file->title_devs ) );
     memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
     dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
 
@@ -434,6 +433,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
     /* Get the full path of the file. */
     if( !findDVDFile( dvd, filename, full_path ) ) return 0;
 
+    fprintf( stderr, "libdvdread: opening %s as file\n", full_path );
     fd = open( full_path, O_RDONLY );
     if( fd < 0 ) return 0;
 
@@ -443,6 +443,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
     dvd_file->lb_start = 0;
     dvd_file->seek_pos = 0;
     memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+    memset( dvd_file->title_devs, -1, sizeof( dvd_file->title_devs ) );
     memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
     dvd_file->filesize = 0;
 
@@ -465,6 +466,7 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd,
     uint32_t start, len;
     dvd_file_t *dvd_file;
 
+    fprintf( stderr, "libdvdread: opening VOB as image\n" );
     if( title == 0 ) {
         sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
     } else {
@@ -510,12 +512,14 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
     dvd_file_t *dvd_file;
     int i;
 
+    fprintf( stderr, "libdvdread: opening VOB as file\n" );
     dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
     if( !dvd_file ) return 0;
     dvd_file->dvd = dvd;
     dvd_file->lb_start = 0;
     dvd_file->seek_pos = 0;
     memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+    memset( dvd_file->title_devs, -1, sizeof( dvd_file->title_devs ) );
     memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
     dvd_file->filesize = 0;
 
@@ -545,6 +549,8 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
         }
         dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
         dvd_file->title_fds[ 0 ] = fd;
+        dvd_file->title_devs[ 0 ] = dvdcss_open( full_path );
+        dvdcss_title( dvd_file->title_devs[0], 0 );
         dvd_file->filesize = dvd_file->title_sizes[ 0 ];
 
     } else {
@@ -562,6 +568,8 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
 
             dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
             dvd_file->title_fds[ i ] = open( full_path, O_RDONLY );
+            dvd_file->title_devs[ i ] = dvdcss_open( full_path );
+            dvdcss_title( dvd_file->title_devs[i], 0 );
             dvd_file->filesize += dvd_file->title_sizes[ i ];
         }
         if( !(dvd_file->title_sizes[ 0 ]) ) {
@@ -628,7 +636,10 @@ void DVDCloseFile( dvd_file_t *dvd_file )
         if( !dvd_file->dvd->isImageFile ) {
             for( i = 0; i < 9; ++i ) {
                 if( dvd_file->title_fds[ i ] >= 0 )
+                {
                    close( dvd_file->title_fds[ i ] );
+            dvdcss_close( dvd_file->title_devs[i] );
+                }
             }
         }
 
@@ -844,26 +855,103 @@ static int64_t DVDReadVBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
                          block_count, vector, DVDCSS_READ_DECRYPT );
 }
 
+static int64_t DVDReadVBlocksPath( dvd_file_t *dvd_file, size_t offset,
+                                 size_t block_count, struct iovec *vector )
+{
+    int i;
+    int ret, ret2;
+    int off;
+
+    ret = 0;
+    ret2 = 0;
+    for( i = 0 ; i < 9 ; ++i )
+    {
+        if( !dvd_file->title_sizes[ i ] )
+        {
+            return 0;
+        }
+
+        if( offset < dvd_file->title_sizes[ i ] )
+        {
+            if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] )
+            {
+                   off = dvdcss_seek( dvd_file->title_devs[ i ], 
+                                  (int)offset, 0 );
+                       if( off != (int)offset )
+                {
+                           fprintf( stderr, "libdvdread: Can't seek to block %d\n", 
+                                     offset );
+                           return 0;
+                       }
+                ret = dvdcss_readv( dvd_file->title_devs[ i ], vector,
+                            (int)block_count, DVDCSS_READ_DECRYPT );
+                break;
+            }
+            else
+            {
+                       int part1_size = dvd_file->title_sizes[ i ] - offset;
+                       /* FIXME: Really needs to be a while loop.
+                          (This is only true if you try and read >1GB at a time) */
+               
+                /* Read part 1 */
+                off = dvdcss_seek( dvd_file->title_devs[ i ], offset, 0 );
+                       if( off != offset )
+                {
+                           fprintf( stderr, "libdvdread: Can't seek to block %d\n", 
+                                    offset );
+                           return 0;
+                       }
+                ret = dvdcss_readv( dvd_file->title_devs[ i ], vector,
+                                    part1_size, DVDCSS_READ_DECRYPT );
+                
+                       if( ret < 0 ) return ret;
+                       /* FIXME: This is wrong if i is the last file in the set. 
+                         also error from this read will not show in ret. */
+               
+                /* Read part 2 */
+                dvdcss_seek( dvd_file->title_devs[ i + 1 ], 0, 0 );
+                ret2 = dvdcss_readv( dvd_file->title_devs[ i + 1 ],
+                        vector + part1_size, (int)(block_count - part1_size),
+                        DVDCSS_READ_DECRYPT );
+                if( ret2 < 0 ) return ret2;
+                       break;
+            }
+        }
+        else
+        {
+            offset -= dvd_file->title_sizes[ i ];
+        }
+    }
+
+    return ( ret + ret2 ) * (int64_t) DVD_VIDEO_LB_LEN;
+}
+
 
 ssize_t DVDReadVBlocks( dvd_file_t *dvd_file, int offset,
                size_t block_count, struct iovec * vector )
 {
     int64_t ret;
 
-    if( dvd_file->dvd->isImageFile ) {
-    ret = DVDReadVBlocksUDF( dvd_file, (uint32_t)offset,
-                block_count, vector );
-    } else {
-  ret = 0;//= DVDReadVBlocksPath( dvd_file, (size_t) offset, 
-//               block_count, vector );
+    if( dvd_file->dvd->isImageFile )
+    {
+        ret = DVDReadVBlocksUDF( dvd_file, (uint32_t)offset,
+                                 block_count, vector );
     }
-    if( ret <= 0 ) {
+    else
+    {
+        ret = DVDReadVBlocksPath( dvd_file, (size_t) offset, 
+                                  block_count, vector );
+    }
+    if( ret <= 0 )
+    {
         return (ssize_t) ret;
     }
+    
     {
       ssize_t sret = (ssize_t) (ret / (int64_t)DVD_VIDEO_LB_LEN );
-      if( sret == 0 ) {
-    fprintf(stderr, "libdvdread: DVDReadVBlocks got %d bytes\n", (int)ret );
+      if( sret == 0 )
+      {
+        fprintf(stderr, "libdvdread: DVDReadVBlocks got %d bytes\n", (int)ret );
       }
       return sret;
     }
index 8c7ccce..fdd1d66 100644 (file)
@@ -3,7 +3,7 @@
  * (hard-linked) and adds a readv call function to tha API.
  *****************************************************************************
  * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>.
- * $Id: dvdread.c,v 1.1 2001/11/25 05:04:38 stef Exp $
+ * $Id: dvdread.c,v 1.2 2002/01/15 05:22:21 stef Exp $
  *
  * Author: Billy Biggs <vektor@dumbterm.net>
  *         Stéphane Borel <stef@via.ecp.fr>
@@ -81,6 +81,7 @@ struct dvd_file_s {
     uint32_t seek_pos;
 
     /* Information required for a directory path drive. */
+    dvdcss_handle title_devs[9];
     size_t title_sizes[ 9 ];
     int title_fds[ 9 ];
 
@@ -119,6 +120,7 @@ static dvd_reader_t *DVDOpenPath( const char *path_root )
 {
     dvd_reader_t *dvd;
 
+    fprintf(stderr, "libdvdread: opening %s as folder\n", path_root );
     dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) );
     if( !dvd ) return 0;
     dvd->isImageFile = 0;
@@ -348,11 +350,13 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
     start = UDFFindFile( dvd, filename, &len );
     if( !start ) return 0;
 
+    fprintf( stderr, "libdvdread: opening %s as image\n", filename );
     dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
     if( !dvd_file ) return 0;
     dvd_file->dvd = dvd;
     dvd_file->lb_start = start;
     dvd_file->seek_pos = 0;
+    memset( dvd_file->title_devs, -1, sizeof( dvd_file->title_devs ) );
     memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
     dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
 
@@ -429,6 +433,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
     /* Get the full path of the file. */
     if( !findDVDFile( dvd, filename, full_path ) ) return 0;
 
+    fprintf( stderr, "libdvdread: opening %s as file\n", full_path );
     fd = open( full_path, O_RDONLY );
     if( fd < 0 ) return 0;
 
@@ -438,6 +443,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
     dvd_file->lb_start = 0;
     dvd_file->seek_pos = 0;
     memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+    memset( dvd_file->title_devs, -1, sizeof( dvd_file->title_devs ) );
     memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
     dvd_file->filesize = 0;
 
@@ -460,6 +466,7 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd,
     uint32_t start, len;
     dvd_file_t *dvd_file;
 
+    fprintf( stderr, "libdvdread: opening VOB as image\n" );
     if( title == 0 ) {
         sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" );
     } else {
@@ -505,12 +512,14 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
     dvd_file_t *dvd_file;
     int i;
 
+    fprintf( stderr, "libdvdread: opening VOB as file\n" );
     dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) );
     if( !dvd_file ) return 0;
     dvd_file->dvd = dvd;
     dvd_file->lb_start = 0;
     dvd_file->seek_pos = 0;
     memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
+    memset( dvd_file->title_devs, -1, sizeof( dvd_file->title_devs ) );
     memset( dvd_file->title_fds, -1, sizeof( dvd_file->title_fds ) );
     dvd_file->filesize = 0;
 
@@ -540,6 +549,8 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
         }
         dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
         dvd_file->title_fds[ 0 ] = fd;
+        dvd_file->title_devs[ 0 ] = dvdcss_open( full_path );
+        dvdcss_title( dvd_file->title_devs[0], 0 );
         dvd_file->filesize = dvd_file->title_sizes[ 0 ];
 
     } else {
@@ -557,6 +568,8 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd,
 
             dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
             dvd_file->title_fds[ i ] = open( full_path, O_RDONLY );
+            dvd_file->title_devs[ i ] = dvdcss_open( full_path );
+            dvdcss_title( dvd_file->title_devs[i], 0 );
             dvd_file->filesize += dvd_file->title_sizes[ i ];
         }
         if( !(dvd_file->title_sizes[ 0 ]) ) {
@@ -623,7 +636,10 @@ void DVDCloseFile( dvd_file_t *dvd_file )
         if( !dvd_file->dvd->isImageFile ) {
             for( i = 0; i < 9; ++i ) {
                 if( dvd_file->title_fds[ i ] >= 0 )
+                {
                    close( dvd_file->title_fds[ i ] );
+            dvdcss_close( dvd_file->title_devs[i] );
+                }
             }
         }
 
@@ -839,26 +855,103 @@ static int64_t DVDReadVBlocksUDF( dvd_file_t *dvd_file, uint32_t offset,
                          block_count, vector, DVDCSS_READ_DECRYPT );
 }
 
+static int64_t DVDReadVBlocksPath( dvd_file_t *dvd_file, size_t offset,
+                                 size_t block_count, struct iovec *vector )
+{
+    int i;
+    int ret, ret2;
+    int off;
+
+    ret = 0;
+    ret2 = 0;
+    for( i = 0 ; i < 9 ; ++i )
+    {
+        if( !dvd_file->title_sizes[ i ] )
+        {
+            return 0;
+        }
+
+        if( offset < dvd_file->title_sizes[ i ] )
+        {
+            if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] )
+            {
+                   off = dvdcss_seek( dvd_file->title_devs[ i ], 
+                                  (int)offset, 0 );
+                       if( off != (int)offset )
+                {
+                           fprintf( stderr, "libdvdread: Can't seek to block %d\n", 
+                                     offset );
+                           return 0;
+                       }
+                ret = dvdcss_readv( dvd_file->title_devs[ i ], vector,
+                            (int)block_count, DVDCSS_READ_DECRYPT );
+                break;
+            }
+            else
+            {
+                       int part1_size = dvd_file->title_sizes[ i ] - offset;
+                       /* FIXME: Really needs to be a while loop.
+                          (This is only true if you try and read >1GB at a time) */
+               
+                /* Read part 1 */
+                off = dvdcss_seek( dvd_file->title_devs[ i ], offset, 0 );
+                       if( off != offset )
+                {
+                           fprintf( stderr, "libdvdread: Can't seek to block %d\n", 
+                                    offset );
+                           return 0;
+                       }
+                ret = dvdcss_readv( dvd_file->title_devs[ i ], vector,
+                                    part1_size, DVDCSS_READ_DECRYPT );
+                
+                       if( ret < 0 ) return ret;
+                       /* FIXME: This is wrong if i is the last file in the set. 
+                         also error from this read will not show in ret. */
+               
+                /* Read part 2 */
+                dvdcss_seek( dvd_file->title_devs[ i + 1 ], 0, 0 );
+                ret2 = dvdcss_readv( dvd_file->title_devs[ i + 1 ],
+                        vector + part1_size, (int)(block_count - part1_size),
+                        DVDCSS_READ_DECRYPT );
+                if( ret2 < 0 ) return ret2;
+                       break;
+            }
+        }
+        else
+        {
+            offset -= dvd_file->title_sizes[ i ];
+        }
+    }
+
+    return ( ret + ret2 ) * (int64_t) DVD_VIDEO_LB_LEN;
+}
+
 
 ssize_t DVDReadVBlocks( dvd_file_t *dvd_file, int offset,
                size_t block_count, struct iovec * vector )
 {
     int64_t ret;
 
-    if( dvd_file->dvd->isImageFile ) {
-    ret = DVDReadVBlocksUDF( dvd_file, (uint32_t)offset,
-                block_count, vector );
-    } else {
-  ret = 0;//= DVDReadVBlocksPath( dvd_file, (size_t) offset, 
-//               block_count, vector );
+    if( dvd_file->dvd->isImageFile )
+    {
+        ret = DVDReadVBlocksUDF( dvd_file, (uint32_t)offset,
+                                 block_count, vector );
     }
-    if( ret <= 0 ) {
+    else
+    {
+        ret = DVDReadVBlocksPath( dvd_file, (size_t) offset, 
+                                  block_count, vector );
+    }
+    if( ret <= 0 )
+    {
         return (ssize_t) ret;
     }
+    
     {
       ssize_t sret = (ssize_t) (ret / (int64_t)DVD_VIDEO_LB_LEN );
-      if( sret == 0 ) {
-    fprintf(stderr, "libdvdread: DVDReadVBlocks got %d bytes\n", (int)ret );
+      if( sret == 0 )
+      {
+        fprintf(stderr, "libdvdread: DVDReadVBlocks got %d bytes\n", (int)ret );
       }
       return sret;
     }