changeset 60:30995ad032cf src

use new memcopy'less read ahead cache
author mroi
date Fri, 12 Jul 2002 15:46:44 +0000
parents 6b90f8ffd8c0
children 6b7520caf9a1
files decoder.h dvdnav.c dvdnav.h read_cache.c read_cache.h
diffstat 5 files changed, 249 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/decoder.h	Fri Jul 12 14:02:52 2002 +0000
+++ b/decoder.h	Fri Jul 12 15:46:44 2002 +0000
@@ -31,7 +31,7 @@
 #include <dvdread/ifo_types.h> /*  vm_cmd_t */
 
 /* Uncomment for tracing */
-#define TRACE
+/* #define TRACE  */
 
 typedef enum {
   LinkNoLink  = 0,
--- a/dvdnav.c	Fri Jul 12 14:02:52 2002 +0000
+++ b/dvdnav.c	Fri Jul 12 15:46:44 2002 +0000
@@ -230,13 +230,6 @@
   fprintf(stderr,"dvdnav:close:called\n");
 #endif
 
-  /* Stop caching */
-
-  if(this->cache) {
-    dvdnav_read_cache_free(this->cache);
-    this->cache = NULL;
-  }
-  
   if (this->file) {
     DVDCloseFile(this->file);
 #ifdef LOG_DEBUG
@@ -257,8 +250,13 @@
     this->file = NULL;
   }
   pthread_mutex_destroy(&this->vm_lock);
-  /* Finally free the entire structure */
-  free(this);
+
+  /* We leave the final freeing of the entire structure to the cache,
+   * because we don't know, if there are still buffers out in the wild,
+   * that must return first. */
+  if(this->cache) {
+    dvdnav_read_cache_free(this->cache);
+  } else free(this);
   
   return S_OK;
 }
@@ -482,16 +480,33 @@
 
   return 1;
 }
+
 /* This is the main get_next_block function which actually gets the media stream video and audio etc.
  * The use of this function is optional, with the application programmer
  * free to implement their own version of this function
  * FIXME: Make the function calls from here public API calls.
  */
+
 dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, unsigned char *buf,
  				      int *event, int *len) {
+  unsigned char *block;
+  dvdnav_status_t status;
+  
+  block = buf;
+  status = dvdnav_get_next_cache_block(this, &block, event, len);
+  if (block != buf) {
+    /* we received a block from the cache, copy it, so we can give it back */
+    memcpy(buf, block, DVD_VIDEO_LB_LEN);
+    dvdnav_free_cache_block(this, block);
+  }
+  return status;
+}
+ 
+dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, unsigned char **buf,
+ 					    int *event, int *len) {
   dvd_state_t *state;
   int result;
-  if(!this || !event || !len || !buf) {
+  if(!this || !event || !len || !buf || !*buf) {
     printerr("Passed a NULL pointer");
     return S_ERR;
   }
@@ -523,7 +538,7 @@
 
     (*event) = DVDNAV_STILL_FRAME;
     (*len) = sizeof(dvdnav_still_event_t);
-    memcpy(buf, &(still_event), sizeof(dvdnav_still_event_t));
+    memcpy(*buf, &(still_event), sizeof(dvdnav_still_event_t));
  
     pthread_mutex_unlock(&this->vm_lock); 
     return S_OK;
@@ -553,7 +568,7 @@
     fprintf(stderr,"libdvdnav:SPU_CLUT_CHANGE\n");
 #endif
     (*len) = sizeof(dvdnav_still_event_t);
-    memcpy(buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
+    memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
     this->spu_clut_changed = 0;
 #ifdef LOG_DEBUG
     fprintf(stderr,"libdvdnav:SPU_CLUT_CHANGE returning S_OK\n");
@@ -572,7 +587,7 @@
     stream_change.physical_wide = vm_get_subp_active_stream(this->vm, 0);
     stream_change.physical_letterbox = vm_get_subp_active_stream(this->vm, 1);
     stream_change.physical_pan_scan = vm_get_subp_active_stream(this->vm, 2);
-    memcpy(buf, &(stream_change), sizeof( dvdnav_spu_stream_change_event_t));
+    memcpy(*buf, &(stream_change), sizeof( dvdnav_spu_stream_change_event_t));
     this->position_current.spu_channel = this->position_next.spu_channel;
 #ifdef LOG_DEBUG
     fprintf(stderr,"libdvdnav:SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change.physical_wide);
@@ -598,7 +613,7 @@
 #endif
     (*len) = sizeof(dvdnav_audio_stream_change_event_t);
     stream_change.physical= vm_get_audio_active_stream( this->vm );
-    memcpy(buf, &(stream_change), sizeof( dvdnav_audio_stream_change_event_t));
+    memcpy(*buf, &(stream_change), sizeof( dvdnav_audio_stream_change_event_t));
     this->position_current.audio_channel = this->position_next.audio_channel;
 #ifdef LOG_DEBUG
     fprintf(stderr,"libdvdnav:AUDIO_STREAM_CHANGE stream_id=%d returning S_OK\n",stream_change.physical);
@@ -619,7 +634,7 @@
     
     (*event) = DVDNAV_HIGHLIGHT;
     (*len) = sizeof(hevent);
-    memcpy(buf, &(hevent), sizeof(hevent));
+    memcpy(*buf, &(hevent), sizeof(hevent));
     pthread_mutex_unlock(&this->vm_lock); 
     return S_OK;
   }
@@ -677,7 +692,7 @@
 
     /* File opened successfully so return a VTS change event */
     (*event) = DVDNAV_VTS_CHANGE;
-    memcpy(buf, &(vts_event), sizeof(vts_event));
+    memcpy(*buf, &(vts_event), sizeof(vts_event));
     (*len) = sizeof(vts_event);
 
     /* On a VTS change, we want to disable any highlights which
@@ -748,7 +763,7 @@
         still_event.length = this->position_current.still;
         (*event) = DVDNAV_STILL_FRAME;
         (*len) = sizeof(dvdnav_still_event_t);
-        memcpy(buf, &(still_event), sizeof(dvdnav_still_event_t));
+        memcpy(*buf, &(still_event), sizeof(dvdnav_still_event_t));
         pthread_mutex_unlock(&this->vm_lock); 
         return S_OK;
       }
@@ -774,7 +789,7 @@
     }
     /* Decode nav into pci and dsi. */
     /* Then get next VOBU info. */
-    if(dvdnav_decode_packet(this, buf, &this->dsi, &this->pci) == 0) {
+    if(dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci) == 0) {
       printerr("Expected NAV packet but none found.");
       pthread_mutex_unlock(&this->vm_lock); 
       return S_ERR;
@@ -963,6 +978,9 @@
 
 /*
  * $Log$
+ * Revision 1.27  2002/07/12 15:46:44  mroi
+ * use new memcopy'less read ahead cache
+ *
  * Revision 1.26  2002/07/06 16:24:54  mroi
  * * fix debug messages
  * * send spu stream change event only, when there are new streams
--- a/dvdnav.h	Fri Jul 12 14:02:52 2002 +0000
+++ b/dvdnav.h	Fri Jul 12 15:46:44 2002 +0000
@@ -208,6 +208,33 @@
 				      int *event, int *len);
 
 /**
+ * This basically does the same as dvdnav_get_next_block. The only difference is
+ * that it avoids a memcopy, when the requested block was found in the cache.
+ * I such a case (cache hit) this function will return a different pointer than
+ * the one handed in, pointing directly into the relevant block in the cache.
+ * Those pointer must _never_ be freed but instead returned to the library via
+ + dvdnav_free_cache_block.
+ *
+ * \param self Pointer to dvdnav_t associated with this operation.
+ * \param buf Buffer (at least 2048 octets) to fill with next block/event structure.
+ *            A different buffer might be returned, if the block was found in the internal cache.
+ * \param event Pointer to int to get event type.
+ * \param len Pointer to int to get the number of octets written into buf.
+ */
+dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *self, unsigned char **buf,
+					    int *event, int *len);
+
+/**
+ * All buffers which came from the internal cache (when dvdnav_get_next_cache_block
+ * returned a buffer different from the one handed in) have to be freed with this
+ * function. Although handing in other buffers not from the cache doesn't cause any harm.
+ *
+ * \param self Pointer to dvdnav_t associated with this operation.
+ * \param buf Buffer received from internal cache.
+ */
+dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf);
+
+/**
  * Get video aspect code.
  *
  * \param self Pointer to dvdnav_t associated with this operation.
--- a/read_cache.c	Fri Jul 12 14:02:52 2002 +0000
+++ b/read_cache.c	Fri Jul 12 15:46:44 2002 +0000
@@ -36,8 +36,7 @@
 */
 
 /* Read-ahead cache structure. */
-#if 0
-/* #if _MULTITHREAD_ */
+#if _MULTITHREAD_
 
 /* For the multithreaded cache, the cache is a ring buffer + writing
  * thread that continuously reads data into the buffer until it is
@@ -67,16 +66,25 @@
 };
 
 #else
-struct read_cache_s {
-  /* Read-ahead cache. */
-  uint8_t      *cache_buffer;
+
+#define READ_CACHE_CHUNKS 10
+
+typedef struct read_cache_chunk_s {
+  uint8_t     *cache_buffer;
   int32_t      cache_start_sector; /* -1 means cache invalid */
   size_t       cache_block_count;
   size_t       cache_malloc_size;
   int          cache_valid;
+  int          usage_count;  /* counts how many buffers where issued from this chunk */
+} read_cache_chunk_t;
+
+struct read_cache_s {
+  read_cache_chunk_t  chunk[READ_CACHE_CHUNKS];
+  int                 current;
+  int                 freeing;  /* is set to one when we are about to dispose the cache */
 
   /* Bit of strange cross-linking going on here :) -- Gotta love C :) */
-  dvdnav_t    *dvd_self;
+  dvdnav_t           *dvd_self;
 };
 #endif
 
@@ -88,8 +96,7 @@
 #define dprintf(fmt, args...) /* Nowt */
 #endif
 
-#if 0
-/* #if _MULTITHREAD_ */
+#if _MULTITHREAD_
 
 void * read_cache_read_thread (void * this_gen) {
   int cont = 1;
@@ -190,6 +197,8 @@
 }
 
 void dvdnav_read_cache_free(read_cache_t* self) {
+  dvdnav_t *tmp;
+  
   pthread_mutex_lock(&self->cache_lock);
 		   
   if(self->buffer) {
@@ -203,8 +212,12 @@
   pthread_join(self->read_thread, NULL);
   
   pthread_mutex_destroy(&self->cache_lock);
-
+  
+  tmp = self->dvd_self;
   free(self);
+  
+  /* We free the main structure, too, because we have no buffers out there. */
+  free(tmp);
 }
 
 /* This function MUST be called whenever self->file changes. */
@@ -250,7 +263,7 @@
 }
 
 /* This function will do the cache read once implemented */
-int dvdnav_read_cache_block( read_cache_t *self, int sector, size_t block_count, uint8_t *buf) {
+int dvdnav_read_cache_block( read_cache_t *self, int sector, size_t block_count, uint8_t **buf) {
   int result, diff;
  
   if(!self)
@@ -272,7 +285,7 @@
 
     if(((self->start + diff) % CACHE_BUFFER_SIZE) + block_count <= CACHE_BUFFER_SIZE) {
       dprintf("************** Single read\n");
-      memcpy(buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), 
+      memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), 
 	     block_count * DVD_VIDEO_LB_LEN);
       self->read_point += block_count;
       pthread_mutex_unlock(&self->cache_lock);
@@ -282,9 +295,9 @@
       int32_t boundary = CACHE_BUFFER_SIZE - self->start;
 
       dprintf("************** Multiple read\n");
-      memcpy(buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), 
+      memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN), 
 	     boundary * DVD_VIDEO_LB_LEN);
-      memcpy(buf + (boundary  * DVD_VIDEO_LB_LEN), self->buffer, 
+      memcpy(*buf + (boundary  * DVD_VIDEO_LB_LEN), self->buffer, 
 	     (block_count-boundary) * DVD_VIDEO_LB_LEN);
       self->read_point += block_count;
       pthread_mutex_unlock(&self->cache_lock);
@@ -295,7 +308,7 @@
     /* Miss */
 
     fprintf(stderr, "DVD read cache miss! (not bad but a performance hit) sector=%d\n", sector); 
-    result = DVDReadBlocks( self->dvd_self->file, sector, block_count, buf);
+    result = DVDReadBlocks( self->dvd_self->file, sector, block_count, *buf);
     self->read_point = sector+block_count;
     if(self->read_point > self->pos + self->size) {
       /* Flush the cache as its not much use */
@@ -313,43 +326,64 @@
   return 0;
 }
 
+dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) {
+  return DVDNAV_STATUS_OK;
+}
+
 #else
 
 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) {
-  read_cache_t *me;
+  read_cache_t *self;
+  int i;
 
-  me = (read_cache_t*)malloc(sizeof(struct read_cache_s));
+  self = (read_cache_t *)malloc(sizeof(read_cache_t));
 
-  if(me) {
-    me->dvd_self = dvd_self;
-
-    dvdnav_read_cache_clear(me);
-    me->cache_buffer = NULL;
+  if(self) {
+    self->current = 0;
+    self->freeing = 0;
+    self->dvd_self = dvd_self;
+    dvdnav_read_cache_clear(self);
+    for (i = 0; i < READ_CACHE_CHUNKS; i++) {
+      self->chunk[i].cache_buffer = NULL;
+      self->chunk[i].cache_block_count = 0;
+      self->chunk[i].usage_count = 0;
+    }
   }
   
-  /* this->cache_start_sector = -1;
-  this->cache_block_count = 0;
-  this->cache_valid = 0; */
-
-  return me;
+  return self;
 }
 
 void dvdnav_read_cache_free(read_cache_t* self) {
-  if(self->cache_buffer) {
-    free(self->cache_buffer);
-    self->cache_buffer = NULL;
-  }
+  dvdnav_t *tmp;
+  int i;
+  
+  self->freeing = 1;
+  for (i = 0; i < READ_CACHE_CHUNKS; i++)
+    if (self->chunk[i].cache_buffer && self->chunk[i].usage_count == 0) {
+      free(self->chunk[i].cache_buffer);
+      self->chunk[i].cache_buffer = NULL;
+    }
+    
+  for (i = 0; i < READ_CACHE_CHUNKS; i++)
+    if (self->chunk[i].cache_buffer) return;
 
+  /* all buffers returned, free everything */
+  tmp = self->dvd_self;
   free(self);
+  free(tmp);
 }
 
 /* This function MUST be called whenever self->file changes. */
 void dvdnav_read_cache_clear(read_cache_t *self) {
+  int i;
+
   if(!self)
    return;
-  
-  self->cache_start_sector = -1;
-  self->cache_valid = 0;
+   
+  for (i = 0; i < READ_CACHE_CHUNKS; i++) {
+    self->chunk[i].cache_start_sector = -1;
+    self->chunk[i].cache_valid = 0;
+  }
 }
 
 #ifdef DVDNAV_PROFILE
@@ -365,75 +399,130 @@
 
 /* This function is called just after reading the NAV packet. */
 void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count) {
-  int result;
+  int i, use, result;
 #ifdef DVDNAV_PROFILE
   struct timeval tv1, tv2, tv3;
   unsigned long long p1, p2, p3;
 #endif
  
   if(!self)
-   return;
+    return;
   
-  if(!self->dvd_self->use_read_ahead) {
-    self->cache_valid = 0;
-    self->cache_start_sector = -1;
+  if(!self->dvd_self->use_read_ahead)
     return;
-  }
-  /* We start with a sensible figure for the first malloc of 500 blocks.
-   * Some DVDs I have seen venture to 450 blocks.
-   * This is so that fewer realloc's happen if at all.
-   */ 
-  if (self->cache_buffer) {
-    if(block_count > self->cache_malloc_size) {
-      self->cache_buffer = realloc(self->cache_buffer, block_count * DVD_VIDEO_LB_LEN);
-      dprintf("libdvdnav:read_cache:pre_cache DVD read realloc happened\n");
-      self->cache_malloc_size = block_count;
-    } 
-  } else {
-    self->cache_buffer = malloc((block_count > 500 ? block_count : 500 )* DVD_VIDEO_LB_LEN);
-    self->cache_malloc_size = (block_count > 500 ? block_count : 500 );
-    dprintf("libdvdnav:read_cache:pre_cache DVD read malloc %d\n", (block_count > 500 ? block_count : 500 )); 
-  }
-  self->cache_start_sector = sector;
-  self->cache_block_count = block_count;
-#ifdef DVDNAV_PROFILE
-  gettimeofday(&tv1, NULL);
-  p1 = dvdnav_rdtsc();
-#endif
-  result = DVDReadBlocks( self->dvd_self->file, sector, block_count, self->cache_buffer);
-#ifdef DVDNAV_PROFILE
-  p2 = dvdnav_rdtsc();
-  gettimeofday(&tv2, NULL);
-  timersub(&tv2, &tv1, &tv3);
-  dprintf("libdvdnav:read_cache:pre_cache DVD read %ld us, profile = %lld, block_count = %d\n", tv3.tv_usec, p2-p1, block_count); 
-#endif
-  self->cache_valid = 1;
-}
 
-/* This function will do the cache read once implemented */
-int dvdnav_read_cache_block( read_cache_t *self, int sector, size_t block_count, uint8_t *buf) {
-  int result;
- 
-  if(!self)
-   return 0;
-
-  if(self->cache_valid && self->dvd_self->use_read_ahead) {
-    if (self->cache_start_sector != -1 ) {
-      if ((sector >= self->cache_start_sector) && 
-	  (sector < self->cache_start_sector + self->cache_block_count)) {
-	memcpy(buf, self->cache_buffer + ((off_t)((off_t)sector - (off_t)self->cache_start_sector) * DVD_VIDEO_LB_LEN), DVD_VIDEO_LB_LEN);
-	return DVD_VIDEO_LB_LEN;
+  /* find a free cache chunk that best fits the required size */
+  use = -1;
+  for (i = 0; i < READ_CACHE_CHUNKS; i++)
+    if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_malloc_size >= block_count &&
+        (use == -1 || self->chunk[use].cache_malloc_size > self->chunk[i].cache_malloc_size))
+      use = i;
+      
+  if (use == -1) {
+    /* we haven't found a cache chunk, so we try to reallocate an existing one */
+    for (i = 0; i < READ_CACHE_CHUNKS; i++)
+      if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_buffer &&
+          (use == -1 || self->chunk[use].cache_malloc_size < self->chunk[i].cache_malloc_size))
+        use = i;
+    if (use >= 0) {
+      self->chunk[use].cache_buffer = realloc(self->chunk[use].cache_buffer,
+        block_count * DVD_VIDEO_LB_LEN);
+      dprintf("pre_cache DVD read realloc happened\n");
+      self->chunk[use].cache_malloc_size = block_count;
+    } else {
+      /* we still haven't found a cache chunk, let's allocate a new one */
+      for (i = 0; i < READ_CACHE_CHUNKS; i++)
+        if (!self->chunk[i].cache_buffer) {
+	  use = i;
+	  break;
+	}
+      if (use >= 0) {
+        /* We start with a sensible figure for the first malloc of 500 blocks.
+         * Some DVDs I have seen venture to 450 blocks.
+         * This is so that fewer realloc's happen if at all.
+         */ 
+	self->chunk[i].cache_buffer = malloc((block_count > 500 ? block_count : 500) * DVD_VIDEO_LB_LEN);
+	self->chunk[i].cache_malloc_size = block_count > 500 ? block_count : 500;
+	dprintf("pre_cache DVD read malloc %d blocks\n",
+	  (block_count > 500 ? block_count : 500 )); 
       }
     }
   }
-  /* Disable dprintf if read cache is disabled. */
-  //if(self->dvd_self->use_read_ahead) {
-  //  dprintf("DVD read cache miss! sector=%d, start=%d, end=%d\n",
-  //           sector, self->cache_start_sector, self->cache_block_count + self->cache_start_sector); 
-  //}
-  result = DVDReadBlocks( self->dvd_self->file, sector, block_count, buf);
-  return result;
+  
+  if (use >= 0) {
+    self->chunk[use].cache_start_sector = sector;
+    self->chunk[use].cache_block_count = block_count;
+    self->current = use;
+#ifdef DVDNAV_PROFILE
+    gettimeofday(&tv1, NULL);
+    p1 = dvdnav_rdtsc();
+#endif
+    result = DVDReadBlocks (self->dvd_self->file, sector, block_count, self->chunk[use].cache_buffer);
+#ifdef DVDNAV_PROFILE
+    p2 = dvdnav_rdtsc();
+    gettimeofday(&tv2, NULL);
+    timersub(&tv2, &tv1, &tv3);
+    dprintf("pre_cache DVD read %ld us, profile = %lld, block_count = %d\n",
+      tv3.tv_usec, p2-p1, block_count); 
+#endif
+    self->chunk[use].cache_valid = 1;
+  } else
+    dprintf("pre_caching was impossible, no cache chunk available\n");
+}
+
+int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf) {
+  int i, use;
+ 
+  if(!self)
+    return 0;
+  
+  use = -1;
+  if(self->dvd_self->use_read_ahead) {
+    /* first check, if sector is in current chunk */
+    read_cache_chunk_t cur = self->chunk[self->current];
+    if (cur.cache_valid && sector >= cur.cache_start_sector &&
+        sector + block_count <= cur.cache_start_sector + cur.cache_block_count)
+      use = self->current;
+    else
+      for (i = 0; i < READ_CACHE_CHUNKS; i++)
+        if (self->chunk[i].cache_valid && sector >= self->chunk[i].cache_start_sector &&
+	    sector + block_count <= self->chunk[i].cache_start_sector + self->chunk[i].cache_block_count)
+	  use = i;
+  }
+  
+  if (use >= 0) {
+    self->chunk[use].usage_count++;
+    *buf = &self->chunk[use].cache_buffer[(sector - self->chunk[use].cache_start_sector) *
+      DVD_VIDEO_LB_LEN * block_count];
+    return DVD_VIDEO_LB_LEN * block_count;
+  } else {
+    if (self->dvd_self->use_read_ahead)
+      dprintf("cache miss on sector %d\n", sector);
+    return DVDReadBlocks(self->dvd_self->file, sector, block_count, *buf);
+  }
+}
+
+dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) {
+  read_cache_t *cache;
+  int i;
+  
+  if (!self)
+    return DVDNAV_STATUS_ERR;
+  
+  cache = self->cache;
+  if (!cache)
+    return DVDNAV_STATUS_ERR;
+    
+  for (i = 0; i < READ_CACHE_CHUNKS; i++)
+    if (cache->chunk[i].cache_buffer && buf >= cache->chunk[i].cache_buffer &&
+        buf < cache->chunk[i].cache_buffer + cache->chunk[i].cache_malloc_size * DVD_VIDEO_LB_LEN)
+      cache->chunk[i].usage_count--;
+      
+  if (cache->freeing)
+    /* when we want to dispose the cache, try freeing it now */
+    dvdnav_read_cache_free(cache);
+    
+  return DVDNAV_STATUS_OK;
 }
 
 #endif
-
--- a/read_cache.h	Fri Jul 12 14:02:52 2002 +0000
+++ b/read_cache.h	Fri Jul 12 15:46:44 2002 +0000
@@ -32,7 +32,7 @@
 /* EXPERIMENTAL: Setting the following to 1 will use an experimental multi-threaded
  *               read-ahead cache. 
  */
-#define _MULTITHREAD_ 1
+#define _MULTITHREAD_ 0
 
 /* Constructor/destructors */
 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self);
@@ -42,7 +42,10 @@
 void dvdnav_read_cache_clear(read_cache_t *self);
 /* This function is called just after reading the NAV packet. */
 void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count);
-/* This function will do the cache read */
-int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t *buf);
+/* This function will do the cache read.
+ * The buffer handed in must be malloced to take one dvd block.
+ * On a cache hit, a different buffer will be returned though.
+ * Those buffers must _never_ be freed. */
+int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf);
 
 #endif /* __DVDNAV_READ_CACHE_H */