[libdvdnav-devel] [PATCH 1/2] dvd_reader: cache IFO and PUB files (only for images files)

Thomas Guillem thomas at gllm.fr
Fri Mar 13 17:03:12 CET 2015


It reduces the number of read/seek access
---
 src/dvd_reader.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 4 deletions(-)

diff --git a/src/dvd_reader.c b/src/dvd_reader.c
index ba4bb01..6857905 100644
--- a/src/dvd_reader.c
+++ b/src/dvd_reader.c
@@ -118,6 +118,10 @@ struct dvd_file_s {
 
   /* Calculated at open-time, size in blocks. */
   ssize_t filesize;
+
+  /* Cache of the dvd_file. If not NULL, the cache corresponds to the whole
+   * dvd_file. Used only for IFO and PUB. */
+  unsigned char *cache;
 };
 
 int InternalUDFReadBlocksRaw( const dvd_reader_t *device, uint32_t lb_number,
@@ -647,7 +651,8 @@ void DVDClose( dvd_reader_t *dvd )
 /**
  * Open an unencrypted file on a DVD image file.
  */
-static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
+static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename,
+                                   int do_cache )
 {
   uint32_t start, len;
   dvd_file_t *dvd_file;
@@ -669,6 +674,25 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename )
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+  dvd_file->cache = NULL;
+
+  /* Read the whole file in cache (unencrypted) if asked and if it doesn't
+   * exceed 128KB */
+  if( do_cache && len < 128 * 1024 ) {
+    int ret;
+
+    dvd_file->cache = malloc( len );
+    if( !dvd_file->cache )
+        return dvd_file;
+
+    ret = InternalUDFReadBlocksRaw( dvd, dvd_file->lb_start,
+                                    dvd_file->filesize, dvd_file->cache,
+                                    DVDINPUT_NOFLAGS );
+    if( ret != dvd_file->filesize ) {
+        free( dvd_file->cache );
+        dvd_file->cache = NULL;
+    }
+  }
 
   return dvd_file;
 }
@@ -766,6 +790,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename )
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
   dvd_file->filesize = 0;
+  dvd_file->cache = NULL;
 
   if( stat( full_path, &fileinfo ) < 0 ) {
     fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename );
@@ -803,6 +828,7 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu )
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
   dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+  dvd_file->cache = NULL;
 
   /* Calculate the complete file size for every file in the VOBS */
   if( !menu ) {
@@ -845,6 +871,7 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu )
   memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) );
   memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
   dvd_file->filesize = 0;
+  dvd_file->cache = NULL;
 
   if( menu ) {
     dvd_input_t dev;
@@ -909,6 +936,7 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
                          dvd_read_domain_t domain )
 {
   char filename[ MAX_UDF_FILE_NAME_LEN ];
+  int do_cache = 0;
 
   /* Check arguments. */
   if( dvd == NULL || titlenum < 0 )
@@ -921,6 +949,7 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
     } else {
       sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum );
     }
+    do_cache = 1;
     break;
   case DVD_READ_INFO_BACKUP_FILE:
     if( titlenum == 0 ) {
@@ -928,6 +957,7 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
     } else {
       sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum );
     }
+    do_cache = 1;
     break;
   case DVD_READ_MENU_VOBS:
     if( dvd->isImageFile ) {
@@ -950,7 +980,7 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum,
   }
 
   if( dvd->isImageFile ) {
-    return DVDOpenFileUDF( dvd, filename );
+    return DVDOpenFileUDF( dvd, filename, do_cache );
   } else {
     return DVDOpenFilePath( dvd, filename );
   }
@@ -969,6 +999,7 @@ void DVDCloseFile( dvd_file_t *dvd_file )
       }
     }
 
+    free( dvd_file->cache );
     free( dvd_file );
     dvd_file = NULL;
   }
@@ -1182,8 +1213,25 @@ static int DVDReadBlocksUDF( const dvd_file_t *dvd_file, uint32_t offset,
                              size_t block_count, unsigned char *data,
                              int encrypted )
 {
-  return InternalUDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset,
-                           block_count, data, encrypted );
+  /* If the cache is present and we don't need to decrypt, use the cache to
+   * feed the data */
+  if( dvd_file->cache && (encrypted & DVDINPUT_READ_DECRYPT) == 0 ) {
+    /* Check if we don't exceed the cache (or file) size */
+    if( block_count + offset > (size_t) dvd_file->filesize )
+      return 0;
+
+    /* Copy the cache at a specified offset into data. offset and block_count
+     * must be converted into bytes */
+    memcpy( data, dvd_file->cache + (off_t)offset * (off_t)DVD_VIDEO_LB_LEN,
+            (off_t)block_count * (off_t)DVD_VIDEO_LB_LEN );
+
+    /* return the amount of blocks copied */
+    return block_count;
+  } else {
+    /* use dvdinput access */
+    return InternalUDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset,
+                             block_count, data, encrypted );
+  }
 }
 
 /* This is using possibly several inputs and starting from an offset of '0'.
-- 
2.1.3



More information about the libdvdnav-devel mailing list