summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvan <[email protected]>2009-05-16 07:00:02 +0000
committervan <[email protected]>2009-05-16 07:00:02 +0000
commit9088803bc54b71516392ba83d7b6c58b55a89be8 (patch)
tree382f64befa66d02475e86d5d09a0414706319bc4
parent8bb84abfb17b321ddaa5e2c5dd2c43486fe3dc29 (diff)
- Handle titles that use more than one PGC (like the one in this thread: http://forum.handbrake.fr/viewtopic.php?f=5&t=10678&p=55575&hilit=genesis#p55620).
- Make pgcn_map local rather than static since there can be simultaneous scans from both GUI and queue service threads and statics aren't thread safe. Also make map 32 bytes since standard allows only 255 PGCs per title. - Fix minor bugs in NextPgcn (used pgcn rather than next_pgcn so tested wrong bit) and dvdnav_seek (missing 'break' & extraneous 'while'). git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2420 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--contrib/libdvdnav/A02-mult-pgc.patch22
-rw-r--r--libhb/dvdnav.c107
2 files changed, 69 insertions, 60 deletions
diff --git a/contrib/libdvdnav/A02-mult-pgc.patch b/contrib/libdvdnav/A02-mult-pgc.patch
new file mode 100644
index 000000000..5ccaa689e
--- /dev/null
+++ b/contrib/libdvdnav/A02-mult-pgc.patch
@@ -0,0 +1,22 @@
+# the bit tested here does not indicate 'random or shuffle' - it only says
+# that the title uses multiple PGCs. Since libdvdnav mostly deals correctly
+# with mult PGC titles (modulo some weirdness when seeking) we need the
+# state to get set correctly.
+--- libdvdnav/src/vm/vm.c.orig 2009-05-13 20:44:12.000000000 -0700
++++ libdvdnav/src/vm/vm.c 2009-05-13 20:46:02.000000000 -0700
+@@ -1758,14 +1758,10 @@
+ if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
+ return 0; /* ?? */
+ pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty;
+- if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) {
++
+ int dummy, part;
+ vm_get_current_title_part(vm, &dummy, &part);
+ (vm->state).PTTN_REG = part;
+- } else {
+- /* FIXME: Handle RANDOM or SHUFFLE titles. */
+- fprintf(MSG_OUT, "libdvdnav: RANDOM or SHUFFLE titles are NOT handled yet.\n");
+- }
+ }
+ return 1;
+ }
diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c
index ee7398161..43aefd44b 100644
--- a/libhb/dvdnav.c
+++ b/libhb/dvdnav.c
@@ -46,9 +46,9 @@ hb_dvd_func_t hb_dvdnav_func =
/***********************************************************************
* Local prototypes
**********************************************************************/
-static void PgcWalkInit( void );
+static void PgcWalkInit( uint32_t pgcn_map[8] );
static int FindChapterIndex( hb_list_t * list, int pgcn, int pgn );
-static int NextPgcn( ifo_handle_t *ifo, int pgcn );
+static int NextPgcn( ifo_handle_t *ifo, int pgcn, uint32_t pgcn_map[8] );
static int FindNextCell( pgc_t *pgc, int cell_cur );
static int dvdtime2msec( dvd_time_t * );
@@ -222,7 +222,8 @@ PttDuration(ifo_handle_t *ifo, int ttn, int pttn, int *blocks, int *last_pgcn)
int i;
// Initialize map of visited pgc's to prevent loops
- PgcWalkInit();
+ uint32_t pgcn_map[8];
+ PgcWalkInit( pgcn_map );
pgcn = ifo->vts_ptt_srpt->title[ttn-1].ptt[pttn-1].pgcn;
pgn = ifo->vts_ptt_srpt->title[ttn-1].ptt[pttn-1].pgn;
if ( pgcn < 1 || pgcn > ifo->vts_pgcit->nr_of_pgci_srp )
@@ -257,7 +258,7 @@ PttDuration(ifo_handle_t *ifo, int ttn, int pttn, int *blocks, int *last_pgcn)
}
*last_pgcn = pgcn;
pgn = 1;
- } while((pgcn = NextPgcn(ifo, pgcn)) != 0);
+ } while((pgcn = NextPgcn(ifo, pgcn, pgcn_map)) != 0);
return duration;
}
@@ -675,7 +676,8 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
}
/* Chapters */
- PgcWalkInit();
+ uint32_t pgcn_map[8];
+ PgcWalkInit( pgcn_map );
c = 0;
do
{
@@ -693,7 +695,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
}
pgn = 1;
- } while ((pgcn = NextPgcn(ifo, pgcn)) != 0);
+ } while ((pgcn = NextPgcn(ifo, pgcn, pgcn_map)) != 0);
hb_log( "scan: title %d has %d chapters", t, c );
@@ -701,11 +703,6 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
count = hb_list_count( title->list_chapter );
for (i = 0; i < count; i++)
{
- int pgcn_next, pgn_next;
- pgc_t * pgc_next;
- hb_chapter_t *chapter_next;
- int pgc_cell_end;
-
chapter = hb_list_item( title->list_chapter, i );
pgcn = chapter->pgcn;
@@ -714,41 +711,19 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
/* Start cell */
chapter->cell_start = pgc->program_map[pgn-1] - 1;
- chapter->block_start =
- pgc->cell_playback[chapter->cell_start].first_sector;
- pgc_cell_end = pgc->nr_of_cells - 1;
-
- /* End cell */
- if( i < count - 1 )
+ chapter->block_start = pgc->cell_playback[chapter->cell_start].first_sector;
+ // if there are no more programs in this pgc, the end cell is the
+ // last cell. Otherwise it's the cell before the start cell of the
+ // next program.
+ if ( pgn == pgc->nr_of_programs )
{
- /* The cell before the starting cell of the next chapter,
- or... */
- chapter_next = hb_list_item( title->list_chapter, i+1 );
- pgcn_next = chapter_next->pgcn;
- pgn_next = chapter_next->pgn;
- pgc_next = ifo->vts_pgcit->pgci_srp[pgcn_next-1].pgc;
- if (pgcn_next == pgcn)
- {
- chapter->cell_end = pgc_next->program_map[pgn_next-1] - 2;
- }
- else
- {
- chapter->cell_end = pgc_cell_end;
- }
- if( chapter->cell_end < 0 )
- {
- /* Huh? */
- free( chapter );
- continue;
- }
+ chapter->cell_end = pgc->nr_of_cells - 1;
}
else
{
- /* ... the last cell of the title */
- chapter->cell_end = pgc_cell_end;
+ chapter->cell_end = pgc->program_map[pgn] - 2;;
}
- chapter->block_end =
- pgc->cell_playback[chapter->cell_end].last_sector;
+ chapter->block_end = pgc->cell_playback[chapter->cell_end].last_sector;
/* Block count, duration */
chapter->block_count = 0;
@@ -868,7 +843,7 @@ static void hb_dvdnav_stop( hb_dvd_t * e )
static int hb_dvdnav_seek( hb_dvd_t * e, float f )
{
hb_dvdnav_t * d = &(e->dvdnav);
- uint64_t sector;
+ uint64_t sector = f * d->title_block_count;
int result, event, len;
uint8_t buf[HB_DVD_READ_BUFFER_SIZE];
int done = 0, ii;
@@ -878,6 +853,26 @@ static int hb_dvdnav_seek( hb_dvd_t * e, float f )
return 0;
}
+ // XXX the current version of libdvdnav can't seek outside the current
+ // PGC. Check if the place we're seeking to is in a different
+ // PGC. Position there & adjust the offset if so.
+ for ( ii = 0; ii < hb_list_count( d->list_chapter ); ++ii )
+ {
+ hb_chapter_t *chapter = hb_list_item( d->list_chapter, ii );
+ if ( chapter->block_start <= sector && sector <= chapter->block_end )
+ {
+ int32_t title, pgcn, pgn;
+ if (dvdnav_current_title_program( d->dvdnav, &title, &pgcn, &pgn ) != DVDNAV_STATUS_OK)
+ hb_log("dvdnav cur pgcn err: %s", dvdnav_err_to_string(d->dvdnav));
+ if ( d->title != title || chapter->pgcn != pgcn )
+ if (dvdnav_program_play(d->dvdnav, d->title, chapter->pgcn, chapter->pgn) != DVDNAV_STATUS_OK)
+ hb_log("dvdnav prog play err: %s", dvdnav_err_to_string(d->dvdnav));
+ // seek sectors are pgc-relative so remove the pgc start sector.
+ sector -= chapter->block_start;
+ break;
+ }
+ }
+
// dvdnav will not let you seek or poll current position
// till it reaches a certain point in parsing. so we
// have to get blocks until we reach a cell
@@ -895,6 +890,7 @@ static int hb_dvdnav_seek( hb_dvd_t * e, float f )
case DVDNAV_BLOCK_OK:
case DVDNAV_CELL_CHANGE:
done = 1;
+ break;
case DVDNAV_STILL_FRAME:
dvdnav_still_skip( d->dvdnav );
@@ -920,9 +916,8 @@ static int hb_dvdnav_seek( hb_dvd_t * e, float f )
default:
break;
}
- } while (!(event == DVDNAV_CELL_CHANGE || event == DVDNAV_BLOCK_OK));
+ }
- sector = f * d->title_block_count;
if (dvdnav_sector_search(d->dvdnav, sector, SEEK_SET) != DVDNAV_STATUS_OK)
{
hb_error( "dvd: dvdnav_sector_search failed - %s",
@@ -1225,36 +1220,28 @@ static int FindNextCell( pgc_t *pgc, int cell_cur )
return cell_next;
}
-static uint8_t pgcn_map[1280];
-
/***********************************************************************
* NextPgcn
***********************************************************************
* Assumes pgc and cell_cur are correctly set, and sets cell_next to the
* cell to be read when we will be done with cell_cur.
+ * Since pg chains can be circularly linked (either from a read error or
+ * deliberately) pgcn_map tracks program chains we've already seen.
+ * There can be at most 255 PGCNs so we need 256 bits = 8 ints to map them.
**********************************************************************/
-static int NextPgcn( ifo_handle_t *ifo, int pgcn )
+static int NextPgcn( ifo_handle_t *ifo, int pgcn, uint32_t pgcn_map[8] )
{
- int byte;
- uint8_t bit;
int next_pgcn;
pgc_t *pgc;
- byte = pgcn >> 3;
- bit = 1 << (pgcn & 0x7);
- pgcn_map[byte] |= bit;
+ pgcn_map[pgcn >> 5] |= (1 << (pgcn & 31));
pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
next_pgcn = pgc->next_pgc_nr;
if ( next_pgcn < 1 || next_pgcn > ifo->vts_pgcit->nr_of_pgci_srp )
return 0;
- byte = next_pgcn >> 3;
- bit = 1 << (pgcn & 0x7);
- if (pgcn_map[byte] & bit)
- return 0;
-
- return next_pgcn;
+ return pgcn_map[next_pgcn >> 5] & (1 << (next_pgcn & 31))? 0 : next_pgcn;
}
/***********************************************************************
@@ -1263,9 +1250,9 @@ static int NextPgcn( ifo_handle_t *ifo, int pgcn )
* Pgc links can loop. I track which have been visited in a bit vector
* Initialize the bit vector to empty.
**********************************************************************/
-static void PgcWalkInit( void )
+static void PgcWalkInit( uint32_t pgcn_map[8] )
{
- memset(pgcn_map, 0, 128);
+ memset(pgcn_map, 0, sizeof(pgcn_map) );
}
/***********************************************************************