This patch never got accepted (probably because it's touches a lot and
made you nervous), but HandBrake has been applying this for 3 years now.

Some discs have large numbers of repeated language units and pgc's that
cause extreme memory consumption and file i/o issues. scanning all the
titles on such discs is unusably slow. detect such repeats and ref-count
the data structures to avoid reading and storing duplicate info.

diff --git a/src/dvdread/ifo_types.h b/src/dvdread/ifo_types.h
index 7db7d34..aa4c9d3 100644
--- a/src/dvdread/ifo_types.h
+++ b/src/dvdread/ifo_types.h
@@ -301,6 +301,7 @@ typedef struct {
   pgc_program_map_t  *program_map;
   cell_playback_t *cell_playback;
   cell_position_t *cell_position;
+  int      ref_count;
 } ATTRIBUTE_PACKED pgc_t;
 #define PGC_SIZE 236U
 
@@ -326,6 +327,7 @@ typedef struct {
   uint16_t zero_1;
   uint32_t last_byte;
   pgci_srp_t *pgci_srp;
+  int      ref_count;
 } ATTRIBUTE_PACKED pgcit_t;
 #define PGCIT_SIZE 8U
 
diff --git a/src/ifo_read.c b/src/ifo_read.c
index a10e36f..8c383bf 100644
--- a/src/ifo_read.c
+++ b/src/ifo_read.c
@@ -87,9 +87,9 @@ static int ifoRead_VOBU_ADMAP_internal(ifo_handle_t *ifofile,
 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
                                   unsigned int offset);
 
-static void ifoFree_PGC(pgc_t *pgc);
+static void ifoFree_PGC(pgc_t **pgc);
 static void ifoFree_PGC_COMMAND_TBL(pgc_command_tbl_t *cmd_tbl);
-static void ifoFree_PGCIT_internal(pgcit_t *pgcit);
+static void ifoFree_PGCIT_internal(pgcit_t **pgcit);
 
 static inline int DVDFileSeekForce_( dvd_file_t *dvd_file, uint32_t offset, int force_size ) {
   return (DVDFileSeekForce(dvd_file, (int)offset, force_size) == (int)offset);
@@ -922,7 +922,6 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
 
     if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl,
                                 offset + pgc->command_tbl_offset)) {
-      free(pgc->command_tbl);
       return 0;
     }
   } else {
@@ -932,13 +931,10 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
   if(pgc->program_map_offset != 0 && pgc->nr_of_programs>0) {
     pgc->program_map = malloc(pgc->nr_of_programs * sizeof(pgc_program_map_t));
     if(!pgc->program_map) {
-      ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
       return 0;
     }
     if(!ifoRead_PGC_PROGRAM_MAP(ifofile, pgc->program_map,pgc->nr_of_programs,
                                 offset + pgc->program_map_offset)) {
-      ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
-      free(pgc->program_map);
       return 0;
     }
   } else {
@@ -948,18 +944,11 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
   if(pgc->cell_playback_offset != 0 && pgc->nr_of_cells>0) {
     pgc->cell_playback = malloc(pgc->nr_of_cells * sizeof(cell_playback_t));
     if(!pgc->cell_playback) {
-      ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
-      if(pgc->program_map)
-        free(pgc->program_map);
       return 0;
     }
     if(!ifoRead_CELL_PLAYBACK_TBL(ifofile, pgc->cell_playback,
                                   pgc->nr_of_cells,
                                   offset + pgc->cell_playback_offset)) {
-      ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
-      if(pgc->program_map)
-        free(pgc->program_map);
-      free(pgc->cell_playback);
       return 0;
     }
   } else {
@@ -969,13 +958,11 @@ static int ifoRead_PGC(ifo_handle_t *ifofile, pgc_t *pgc, unsigned int offset) {
   if(pgc->cell_position_offset != 0 && pgc->nr_of_cells>0) {
     pgc->cell_position = malloc(pgc->nr_of_cells * sizeof(cell_position_t));
     if(!pgc->cell_position) {
-      ifoFree_PGC(pgc);
       return 0;
     }
     if(!ifoRead_CELL_POSITION_TBL(ifofile, pgc->cell_position,
                                   pgc->nr_of_cells,
                                   offset + pgc->cell_position_offset)) {
-      ifoFree_PGC(pgc);
       return 0;
     }
   } else {
@@ -998,29 +985,33 @@ int ifoRead_FP_PGC(ifo_handle_t *ifofile) {
   if(ifofile->vmgi_mat->first_play_pgc == 0)
     return 1;
 
-  ifofile->first_play_pgc = (pgc_t *)malloc(sizeof(pgc_t));
+  ifofile->first_play_pgc = (pgc_t *)calloc(1, sizeof(pgc_t));
   if(!ifofile->first_play_pgc)
     return 0;
 
+  ifofile->first_play_pgc->ref_count = 1;
   if(!ifoRead_PGC(ifofile, ifofile->first_play_pgc,
                   ifofile->vmgi_mat->first_play_pgc)) {
-    free(ifofile->first_play_pgc);
-    ifofile->first_play_pgc = 0;
+    ifoFree_PGC(&ifofile->first_play_pgc);
     return 0;
   }
 
   return 1;
 }
 
-static void ifoFree_PGC(pgc_t *pgc) {
-  if(pgc) {
-    ifoFree_PGC_COMMAND_TBL(pgc->command_tbl);
-    if(pgc->program_map)
-      free(pgc->program_map);
-    if(pgc->cell_playback)
-      free(pgc->cell_playback);
-    if(pgc->cell_position)
-      free(pgc->cell_position);
+static void ifoFree_PGC(pgc_t **pgc) {
+  if(pgc && *pgc && (--(*pgc)->ref_count) <= 0) {
+    ifoFree_PGC_COMMAND_TBL((*pgc)->command_tbl);
+    if((*pgc)->program_map)
+      free((*pgc)->program_map);
+    if((*pgc)->cell_playback)
+      free((*pgc)->cell_playback);
+    if((*pgc)->cell_position)
+      free((*pgc)->cell_position);
+    free(*pgc);
+  }
+  if (pgc) {
+    *pgc = NULL;
   }
 }
 
@@ -1029,9 +1020,7 @@ void ifoFree_FP_PGC(ifo_handle_t *ifofile) {
     return;
 
   if(ifofile->first_play_pgc) {
-    ifoFree_PGC(ifofile->first_play_pgc);
-    free(ifofile->first_play_pgc);
-    ifofile->first_play_pgc = 0;
+    ifoFree_PGC(&ifofile->first_play_pgc);
   }
 }
 
@@ -1263,6 +1252,13 @@ int ifoRead_VTS_PTT_SRPT(ifo_handle_t *ifofile) {
       CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); /* ?? */
       CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn != 0);
       CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn < 100); /* ?? */
+      if (vts_ptt_srpt->title[i].ptt[j].pgcn == 0 ||
+          vts_ptt_srpt->title[i].ptt[j].pgcn >= 1000 ||
+          vts_ptt_srpt->title[i].ptt[j].pgn == 0 ||
+          vts_ptt_srpt->title[i].ptt[j].pgn >= 100) {
+        return 0;
+      }
+
     }
   }
 
@@ -1832,10 +1828,11 @@ int ifoRead_PGCIT(ifo_handle_t *ifofile) {
   if(ifofile->vtsi_mat->vts_pgcit == 0) /* mandatory */
     return 0;
 
-  ifofile->vts_pgcit = (pgcit_t *)malloc(sizeof(pgcit_t));
+  ifofile->vts_pgcit = (pgcit_t *)calloc(1, sizeof(pgcit_t));
   if(!ifofile->vts_pgcit)
     return 0;
 
+  ifofile->vts_pgcit->ref_count = 1;
   if(!ifoRead_PGCIT_internal(ifofile, ifofile->vts_pgcit,
                              ifofile->vtsi_mat->vts_pgcit * DVD_BLOCK_LEN)) {
     free(ifofile->vts_pgcit);
@@ -1846,6 +1843,17 @@ int ifoRead_PGCIT(ifo_handle_t *ifofile) {
   return 1;
 }
 
+static int find_dup_pgc(pgci_srp_t *pgci_srp, uint32_t start_byte, int count) {
+  int i;
+
+  for(i = 0; i < count; i++) {
+    if(pgci_srp[i].pgc_start_byte == start_byte) {
+      return i;
+    }
+  }
+  return -1;
+}
+
 static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
                                   unsigned int offset) {
   int i, info_length;
@@ -1894,21 +1902,26 @@ static int ifoRead_PGCIT_internal(ifo_handle_t *ifofile, pgcit_t *pgcit,
     CHECK_VALUE(pgcit->pgci_srp[i].pgc_start_byte + PGC_SIZE <= pgcit->last_byte+1);
 
   for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
-    pgcit->pgci_srp[i].pgc = malloc(sizeof(pgc_t));
+    int dup;
+    if((dup = find_dup_pgc(pgcit->pgci_srp, pgcit->pgci_srp[i].pgc_start_byte, i)) >= 0) {
+      pgcit->pgci_srp[i].pgc = pgcit->pgci_srp[dup].pgc;
+      pgcit->pgci_srp[i].pgc->ref_count++;
+      continue;
+    }
+    pgcit->pgci_srp[i].pgc = calloc(1, sizeof(pgc_t));
     if(!pgcit->pgci_srp[i].pgc) {
       int j;
       for(j = 0; j < i; j++) {
-        ifoFree_PGC(pgcit->pgci_srp[j].pgc);
-        free(pgcit->pgci_srp[j].pgc);
+        ifoFree_PGC(&pgcit->pgci_srp[j].pgc);
       }
       goto fail;
     }
+    pgcit->pgci_srp[i].pgc->ref_count = 1;
     if(!ifoRead_PGC(ifofile, pgcit->pgci_srp[i].pgc,
                     offset + pgcit->pgci_srp[i].pgc_start_byte)) {
       int j;
-      for(j = 0; j < i; j++) {
-        ifoFree_PGC(pgcit->pgci_srp[j].pgc);
-        free(pgcit->pgci_srp[j].pgc);
+      for(j = 0; j <= i; j++) {
+        ifoFree_PGC(&pgcit->pgci_srp[j].pgc);
       }
       free(pgcit->pgci_srp[i].pgc);
       goto fail;
@@ -1922,16 +1935,17 @@ fail:
   return 0;
 }
 
-static void ifoFree_PGCIT_internal(pgcit_t *pgcit) {
-  if(pgcit) {
-    int i;
-    for(i = 0; i < pgcit->nr_of_pgci_srp; i++)
-    {
-      ifoFree_PGC(pgcit->pgci_srp[i].pgc);
-      free(pgcit->pgci_srp[i].pgc);
+static void ifoFree_PGCIT_internal(pgcit_t **pgcit) {
+    if(pgcit && *pgcit && (--(*pgcit)->ref_count <= 0)) {
+        int i;
+        for(i = 0; i < (*pgcit)->nr_of_pgci_srp; i++)
+            ifoFree_PGC(&(*pgcit)->pgci_srp[i].pgc);
+        free((*pgcit)->pgci_srp);
+        free(*pgcit);
+    }
+    if (pgcit) {
+        *pgcit = NULL;
     }
-    free(pgcit->pgci_srp);
-  }
 }
 
 void ifoFree_PGCIT(ifo_handle_t *ifofile) {
@@ -1939,12 +1953,20 @@ void ifoFree_PGCIT(ifo_handle_t *ifofile) {
     return;
 
   if(ifofile->vts_pgcit) {
-    ifoFree_PGCIT_internal(ifofile->vts_pgcit);
-    free(ifofile->vts_pgcit);
-    ifofile->vts_pgcit = 0;
+    ifoFree_PGCIT_internal(&ifofile->vts_pgcit);
   }
 }
 
+static int find_dup_lut(pgci_lu_t *lu, uint32_t start_byte, int count) {
+  int i;
+
+  for(i = 0; i < count; i++) {
+    if(lu[i].lang_start_byte == start_byte) {
+      return i;
+    }
+  }
+  return -1;
+}
 
 int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
   pgci_ut_t *pgci_ut;
@@ -2038,27 +2060,31 @@ int ifoRead_PGCI_UT(ifo_handle_t *ifofile) {
   }
 
   for(i = 0; i < pgci_ut->nr_of_lus; i++) {
+    int dup;
+    if((dup = find_dup_lut(pgci_ut->lu, pgci_ut->lu[i].lang_start_byte, i)) >= 0) {
+      pgci_ut->lu[i].pgcit = pgci_ut->lu[dup].pgcit;
+      pgci_ut->lu[i].pgcit->ref_count++;
+      continue;
+    }
     pgci_ut->lu[i].pgcit = malloc(sizeof(pgcit_t));
     if(!pgci_ut->lu[i].pgcit) {
       unsigned int j;
       for(j = 0; j < i; j++) {
-        ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
-        free(pgci_ut->lu[j].pgcit);
+        ifoFree_PGCIT_internal(&pgci_ut->lu[j].pgcit);
       }
       free(pgci_ut->lu);
       free(pgci_ut);
       ifofile->pgci_ut = 0;
       return 0;
     }
+    pgci_ut->lu[i].pgcit->ref_count = 1;
     if(!ifoRead_PGCIT_internal(ifofile, pgci_ut->lu[i].pgcit,
                                sector * DVD_BLOCK_LEN
                                + pgci_ut->lu[i].lang_start_byte)) {
       unsigned int j;
-      for(j = 0; j < i; j++) {
-        ifoFree_PGCIT_internal(pgci_ut->lu[j].pgcit);
-        free(pgci_ut->lu[j].pgcit);
+      for(j = 0; j <= i; j++) {
+        ifoFree_PGCIT_internal(&pgci_ut->lu[j].pgcit);
       }
-      free(pgci_ut->lu[i].pgcit);
       free(pgci_ut->lu);
       free(pgci_ut);
       ifofile->pgci_ut = 0;
@@ -2080,8 +2106,7 @@ void ifoFree_PGCI_UT(ifo_handle_t *ifofile) {
 
   if(ifofile->pgci_ut) {
     for(i = 0; i < ifofile->pgci_ut->nr_of_lus; i++) {
-      ifoFree_PGCIT_internal(ifofile->pgci_ut->lu[i].pgcit);
-      free(ifofile->pgci_ut->lu[i].pgcit);
+      ifoFree_PGCIT_internal(&ifofile->pgci_ut->lu[i].pgcit);
     }
     free(ifofile->pgci_ut->lu);
     free(ifofile->pgci_ut);
_______________________________________________
DVDnav-discuss mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/dvdnav-discuss

Reply via email to