# HG changeset patch # User rathann # Date 1355087279 0 # Node ID 8e12b8e01713ad01c9e56ef51b490664c435dbae # Parent 133be2fe0eefa6e3284608152cea28d7029a7982 Accommodate duplicate language units and pgcs. Many dvd's are showing up that have titles that have numerous repeated language unit tables and pgc's. The new release "Up" is an example. I believe "Dark Knight" also exhibits this. When scanning such discs with lsdvd (and other programs that scan all titles), libdvdread will consume many GB of data for these repeated elements and gets very slow (e.g hours to read all titles) on OS X due to reading the duplicate data from uncached raw devices. This patch detects duplicates and reference counts pgc's and pgcit's. When a duplicate is detected, a reference count is incremented instead of allocating new memory and re-reading the data. Patch by John Stebbins. diff -r 133be2fe0eef -r 8e12b8e01713 dvdread/ifo_types.h --- a/dvdread/ifo_types.h Fri Oct 07 16:56:02 2011 +0000 +++ b/dvdread/ifo_types.h Sun Dec 09 21:07:59 2012 +0000 @@ -301,6 +301,7 @@ 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 @@ 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 -r 133be2fe0eef -r 8e12b8e01713 ifo_read.c --- a/ifo_read.c Fri Oct 07 16:56:02 2011 +0000 +++ b/ifo_read.c Sun Dec 09 21:07:59 2012 +0000 @@ -87,9 +87,9 @@ 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); @@ -923,7 +923,6 @@ if(!ifoRead_PGC_COMMAND_TBL(ifofile, pgc->command_tbl, offset + pgc->command_tbl_offset)) { - free(pgc->command_tbl); return 0; } } else { @@ -933,13 +932,10 @@ 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 { @@ -949,18 +945,11 @@ 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 { @@ -970,13 +959,11 @@ 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 { @@ -999,29 +986,33 @@ 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; } } @@ -1030,9 +1021,7 @@ 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); } } @@ -1250,6 +1239,13 @@ 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; + } + } } @@ -1434,7 +1430,6 @@ if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */ ifofile->vts_tmapt = NULL; - fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n"); return 1; } @@ -1818,10 +1813,11 @@ 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); @@ -1832,6 +1828,17 @@ 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; @@ -1880,21 +1887,26 @@ 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; @@ -1908,16 +1920,19 @@ return 0; } -static void ifoFree_PGCIT_internal(pgcit_t *pgcit) { - if(pgcit) { +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++) + for(i = 0; i < (*pgcit)->nr_of_pgci_srp; i++) { - ifoFree_PGC(pgcit->pgci_srp[i].pgc); - free(pgcit->pgci_srp[i].pgc); + ifoFree_PGC(&(*pgcit)->pgci_srp[i].pgc); + free(&(*pgcit)->pgci_srp[i].pgc); } - free(pgcit->pgci_srp); + free((*pgcit)->pgci_srp); + free(*pgcit); } + if (pgcit) + *pgcit = NULL; } void ifoFree_PGCIT(ifo_handle_t *ifofile) { @@ -1925,12 +1940,20 @@ 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; @@ -2024,27 +2047,31 @@ } 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; @@ -2066,8 +2093,7 @@ 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);