summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/libdvdnav/A01-program-info.patch214
-rw-r--r--libhb/common.h2
-rw-r--r--libhb/dvd.c11
-rw-r--r--libhb/dvd.h31
-rw-r--r--libhb/dvdnav.c437
-rw-r--r--libhb/internal.h2
-rw-r--r--libhb/reader.c2
-rw-r--r--libhb/scan.c2
8 files changed, 525 insertions, 176 deletions
diff --git a/contrib/libdvdnav/A01-program-info.patch b/contrib/libdvdnav/A01-program-info.patch
new file mode 100644
index 000000000..531741b84
--- /dev/null
+++ b/contrib/libdvdnav/A01-program-info.patch
@@ -0,0 +1,214 @@
+diff -Naur libdvdnav.orig/src/dvdnav/dvdnav.h libdvdnav/src/dvdnav/dvdnav.h
+--- libdvdnav.orig/src/dvdnav/dvdnav.h 2009-03-13 18:28:22.000000000 -0700
++++ libdvdnav/src/dvdnav/dvdnav.h 2009-04-30 10:56:29.000000000 -0700
+@@ -279,6 +279,11 @@
+ dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part);
+
+ /*
++ * Plays the specified title, starting from the specified program
++ */
++dvdnav_status_t dvdnav_program_play(dvdnav_t *this, int32_t title, int32_t pgcn, int32_t pgn);
++
++/*
+ * Stores in *times an array (that the application *must* free) of
+ * dvdtimes corresponding to the chapter times for the chosen title.
+ * *duration will have the duration of the title
+@@ -320,6 +325,13 @@
+ int32_t *part);
+
+ /*
++ * Return the title number, pgcn and pgn currently being played.
++ * A title of 0 indicates, we are in a menu.
++ */
++dvdnav_status_t dvdnav_current_title_program(dvdnav_t *self, int32_t *title,
++ int32_t *pgcn, int32_t *pgn);
++
++/*
+ * Return the current position (in blocks) within the current
+ * title and the length (in blocks) of said title.
+ *
+diff -Naur libdvdnav.orig/src/navigation.c libdvdnav/src/navigation.c
+--- libdvdnav.orig/src/navigation.c 2009-01-08 14:57:11.000000000 -0800
++++ libdvdnav/src/navigation.c 2009-04-30 10:55:47.000000000 -0700
+@@ -122,10 +122,90 @@
+ return DVDNAV_STATUS_ERR;
+ }
+
++dvdnav_status_t dvdnav_current_title_program(dvdnav_t *this, int32_t *title, int32_t *pgcn, int32_t *pgn) {
++ int32_t retval;
++ int32_t part;
++
++ pthread_mutex_lock(&this->vm_lock);
++ if (!this->vm->vtsi || !this->vm->vmgi) {
++ printerr("Bad VM state.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++ if (!this->started) {
++ printerr("Virtual DVD machine not started.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++ if (!this->vm->state.pgc) {
++ printerr("No current PGC.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++ if ( (this->vm->state.domain == VTSM_DOMAIN)
++ || (this->vm->state.domain == VMGM_DOMAIN) ) {
++ /* Get current Menu ID: into *part. */
++ if(! vm_get_current_menu(this->vm, &part)) {
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++ if (part > -1) {
++ *title = 0;
++ *pgcn = this->vm->state.pgcN;
++ *pgn = this->vm->state.pgN;
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_OK;
++ }
++ }
++ if (this->vm->state.domain == VTS_DOMAIN) {
++ retval = vm_get_current_title_part(this->vm, title, &part);
++ *pgcn = this->vm->state.pgcN;
++ *pgn = this->vm->state.pgN;
++ pthread_mutex_unlock(&this->vm_lock);
++ return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
++ }
++ printerr("Not in a title or menu.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++}
++
+ dvdnav_status_t dvdnav_title_play(dvdnav_t *this, int32_t title) {
+ return dvdnav_part_play(this, title, 1);
+ }
+
++dvdnav_status_t dvdnav_program_play(dvdnav_t *this, int32_t title, int32_t pgcn, int32_t pgn) {
++ int32_t retval;
++
++ pthread_mutex_lock(&this->vm_lock);
++ if (!this->vm->vmgi) {
++ printerr("Bad VM state.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++ if (!this->started) {
++ /* don't report an error but be nice */
++ vm_start(this->vm);
++ this->started = 1;
++ }
++ if (!this->vm->state.pgc) {
++ printerr("No current PGC.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++ if((title < 1) || (title > this->vm->vmgi->tt_srpt->nr_of_srpts)) {
++ printerr("Title out of range.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++
++ retval = vm_jump_title_program(this->vm, title, pgcn, pgn);
++ if (retval)
++ this->vm->hop_channel++;
++ pthread_mutex_unlock(&this->vm_lock);
++
++ return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
++}
++
+ dvdnav_status_t dvdnav_part_play(dvdnav_t *this, int32_t title, int32_t part) {
+ int32_t retval;
+
+diff -Naur libdvdnav.orig/src/vm/vm.c libdvdnav/src/vm/vm.c
+--- libdvdnav.orig/src/vm/vm.c 2009-03-13 18:28:22.000000000 -0700
++++ libdvdnav/src/vm/vm.c 2009-04-30 11:07:35.000000000 -0700
+@@ -83,6 +83,8 @@
+ static int set_PTT(vm_t *vm, int tt, int ptt);
+ static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn);
+ static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part);
++static int set_PROG(vm_t *vm, int tt, int pgcn, int pgn);
++static int set_VTS_PROG(vm_t *vm, int vtsN, int vts_ttn, int pgcn, int pgn);
+ static int set_FP_PGC(vm_t *vm);
+ static int set_MENU(vm_t *vm, int menu);
+ static int set_PGCN(vm_t *vm, int pgcN);
+@@ -516,6 +518,24 @@
+ return 1;
+ }
+
++int vm_jump_title_program(vm_t *vm, int title, int pgcn, int pgn) {
++ link_t link;
++
++ if(!set_PROG(vm, title, pgcn, pgn))
++ return 0;
++ /* Some DVDs do not want us to jump directly into a title and have
++ * PGC pre commands taking us back to some menu. Since we do not like that,
++ * we do not execute PGC pre commands that would do a jump. */
++ /* process_command(vm, play_PGC_PG(vm, (vm->state).pgN)); */
++ link = play_PGC_PG(vm, (vm->state).pgN);
++ if (link.command != PlayThis)
++ /* jump occured -> ignore it and play the PG anyway */
++ process_command(vm, play_PG(vm));
++ else
++ process_command(vm, link);
++ return 1;
++}
++
+ int vm_jump_title_part(vm_t *vm, int title, int part) {
+ link_t link;
+
+@@ -1644,6 +1664,42 @@
+ return res;
+ }
+
++static int set_PROG(vm_t *vm, int tt, int pgcn, int pgn) {
++ assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts);
++ return set_VTS_PROG(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr,
++ vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, pgcn, pgn);
++}
++
++static int set_VTS_PROG(vm_t *vm, int vtsN, int vts_ttn, int pgcn, int pgn) {
++ int pgcN, pgN, res, title, part;
++
++ (vm->state).domain = VTS_DOMAIN;
++
++ if (vtsN != (vm->state).vtsN)
++ if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN)) /* Also sets (vm->state).vtsN */
++ return 0;
++
++ if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts)) {
++ return 0;
++ }
++
++ pgcN = pgcn;
++ pgN = pgn;
++
++ (vm->state).TT_PGCN_REG = pgcN;
++ (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn);
++ assert( (vm->state.TTN_REG) != 0 );
++ (vm->state).VTS_TTN_REG = vts_ttn;
++ (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */
++ /* Any other registers? */
++
++ res = set_PGCN(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */
++ (vm->state).pgN = pgN;
++ vm_get_current_title_part(vm, &title, &part);
++ (vm->state).PTTN_REG = part;
++ return res;
++}
++
+ static int set_FP_PGC(vm_t *vm) {
+ (vm->state).domain = FP_DOMAIN;
+ if (!vm->vmgi->first_play_pgc) {
+diff -Naur libdvdnav.orig/src/vm/vm.h libdvdnav/src/vm/vm.h
+--- libdvdnav.orig/src/vm/vm.h 2009-03-13 18:28:22.000000000 -0700
++++ libdvdnav/src/vm/vm.h 2009-04-30 10:57:02.000000000 -0700
+@@ -139,6 +139,7 @@
+ int vm_jump_pg(vm_t *vm, int pg);
+ int vm_jump_cell_block(vm_t *vm, int cell, int block);
+ int vm_jump_title_part(vm_t *vm, int title, int part);
++int vm_jump_title_program(vm_t *vm, int title, int pgcn, int pgn);
+ int vm_jump_top_pg(vm_t *vm);
+ int vm_jump_next_pg(vm_t *vm);
+ int vm_jump_prev_pg(vm_t *vm);
diff --git a/libhb/common.h b/libhb/common.h
index 73ebfda76..1c58286fe 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -422,6 +422,8 @@ struct hb_audio_s
struct hb_chapter_s
{
int index;
+ int pgcn;
+ int pgn;
int cell_start;
int cell_end;
int block_start;
diff --git a/libhb/dvd.c b/libhb/dvd.c
index 8bc61944f..cf6eefe49 100644
--- a/libhb/dvd.c
+++ b/libhb/dvd.c
@@ -16,7 +16,7 @@ static void hb_dvdread_close( hb_dvd_t ** _d );
static char * hb_dvdread_name( char * path );
static int hb_dvdread_title_count( hb_dvd_t * d );
static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * d, int t );
-static int hb_dvdread_start( hb_dvd_t * d, int title, int chapter );
+static int hb_dvdread_start( hb_dvd_t * d, hb_title_t *title, int chapter );
static void hb_dvdread_stop( hb_dvd_t * d );
static int hb_dvdread_seek( hb_dvd_t * d, float f );
static int hb_dvdread_read( hb_dvd_t * d, hb_buffer_t * b );
@@ -651,15 +651,16 @@ cleanup:
***********************************************************************
* Title and chapter start at 1
**********************************************************************/
-static int hb_dvdread_start( hb_dvd_t * e, int title, int chapter )
+static int hb_dvdread_start( hb_dvd_t * e, hb_title_t *title, int chapter )
{
hb_dvdread_t *d = &(e->dvdread);
int pgc_id, pgn;
int i;
+ int t = title->index;
/* Open the IFO and the VOBs for this title */
- d->vts = d->vmg->tt_srpt->title[title-1].title_set_nr;
- d->ttn = d->vmg->tt_srpt->title[title-1].vts_ttn;
+ d->vts = d->vmg->tt_srpt->title[t-1].title_set_nr;
+ d->ttn = d->vmg->tt_srpt->title[t-1].vts_ttn;
if( !( d->ifo = ifoOpen( d->reader, d->vts ) ) )
{
hb_error( "dvd: ifoOpen failed for VTS %d", d->vts );
@@ -1257,7 +1258,7 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
return dvd_methods->title_scan(d, t);
}
-int hb_dvd_start( hb_dvd_t * d, int title, int chapter )
+int hb_dvd_start( hb_dvd_t * d, hb_title_t *title, int chapter )
{
return dvd_methods->start(d, title, chapter);
}
diff --git a/libhb/dvd.h b/libhb/dvd.h
index 811efe5b6..bcba78ea4 100644
--- a/libhb/dvd.h
+++ b/libhb/dvd.h
@@ -49,8 +49,9 @@ struct hb_dvdnav_s
dvd_reader_t * reader;
ifo_handle_t * vmg;
int title;
- int title_block_count;
+ int title_block_count;
int chapter;
+ hb_list_t * list_chapter;
int stopped;
};
@@ -59,25 +60,25 @@ typedef struct hb_dvdread_s hb_dvdread_t;
union hb_dvd_s
{
- hb_dvdread_t dvdread;
- hb_dvdnav_t dvdnav;
+ hb_dvdread_t dvdread;
+ hb_dvdnav_t dvdnav;
};
struct hb_dvd_func_s
{
- hb_dvd_t * (* init) ( char * );
- void (* close) ( hb_dvd_t ** );
- char * (* name) ( char * );
- int (* title_count) ( hb_dvd_t * );
- hb_title_t * (* title_scan) ( hb_dvd_t *, int );
- int (* start) ( hb_dvd_t *, int, int );
- void (* stop) ( hb_dvd_t * );
- int (* seek) ( hb_dvd_t *, float );
- int (* read) ( hb_dvd_t *, hb_buffer_t * );
- int (* chapter) ( hb_dvd_t * );
- int (* angle_count) ( hb_dvd_t * );
- void (* set_angle) ( hb_dvd_t *, int );
+ hb_dvd_t * (* init) ( char * );
+ void (* close) ( hb_dvd_t ** );
+ char * (* name) ( char * );
+ int (* title_count) ( hb_dvd_t * );
+ hb_title_t * (* title_scan) ( hb_dvd_t *, int );
+ int (* start) ( hb_dvd_t *, hb_title_t *, int );
+ void (* stop) ( hb_dvd_t * );
+ int (* seek) ( hb_dvd_t *, float );
+ int (* read) ( hb_dvd_t *, hb_buffer_t * );
+ int (* chapter) ( hb_dvd_t * );
+ int (* angle_count) ( hb_dvd_t * );
+ void (* set_angle) ( hb_dvd_t *, int );
};
typedef struct hb_dvd_func_s hb_dvd_func_t;
diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c
index eee9d28b9..ee7398161 100644
--- a/libhb/dvdnav.c
+++ b/libhb/dvdnav.c
@@ -18,7 +18,7 @@ static char * hb_dvdnav_name( char * path );
static hb_dvd_t * hb_dvdnav_init( char * path );
static int hb_dvdnav_title_count( hb_dvd_t * d );
static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * d, int t );
-static int hb_dvdnav_start( hb_dvd_t * d, int title, int chapter );
+static int hb_dvdnav_start( hb_dvd_t * d, hb_title_t *title, int chapter );
static void hb_dvdnav_stop( hb_dvd_t * d );
static int hb_dvdnav_seek( hb_dvd_t * d, float f );
static int hb_dvdnav_read( hb_dvd_t * d, hb_buffer_t * b );
@@ -46,9 +46,11 @@ hb_dvd_func_t hb_dvdnav_func =
/***********************************************************************
* Local prototypes
**********************************************************************/
+static void PgcWalkInit( void );
+static int FindChapterIndex( hb_list_t * list, int pgcn, int pgn );
+static int NextPgcn( ifo_handle_t *ifo, int pgcn );
static int FindNextCell( pgc_t *pgc, int cell_cur );
static int dvdtime2msec( dvd_time_t * );
-//static int hb_dvdnav_is_break( hb_dvdnav_t * d );
hb_dvd_func_t * hb_dvdnav_methods( void )
{
@@ -88,7 +90,7 @@ static char * hb_dvdnav_name( char * path )
static int hb_dvdnav_reset( hb_dvdnav_t * d )
{
if ( d->dvdnav )
- dvdnav_close( d->dvdnav );
+ dvdnav_close( d->dvdnav );
/* Open device */
if( dvdnav_open(&d->dvdnav, d->path) != DVDNAV_STATUS_OK )
@@ -119,7 +121,7 @@ static int hb_dvdnav_reset( hb_dvdnav_t * d )
dvdnav_err_to_string(d->dvdnav));
goto fail;
}
- return 1;
+ return 1;
fail:
if( d->dvdnav ) dvdnav_close( d->dvdnav );
@@ -210,6 +212,55 @@ static int hb_dvdnav_title_count( hb_dvd_t * e )
return titles;
}
+static uint64_t
+PttDuration(ifo_handle_t *ifo, int ttn, int pttn, int *blocks, int *last_pgcn)
+{
+ int pgcn, pgn;
+ pgc_t * pgc;
+ uint64_t duration = 0;
+ int cell_start, cell_end;
+ int i;
+
+ // Initialize map of visited pgc's to prevent loops
+ PgcWalkInit();
+ 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 )
+ {
+ hb_error( "invalid PGC ID %d, skipping", pgcn );
+ return 0;
+ }
+
+ if( pgn <= 0 || pgn > 99 )
+ {
+ hb_error( "scan: pgn %d not valid, skipping", pgn );
+ return 0;
+ }
+
+ *blocks = 0;
+ do
+ {
+ pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
+ if (!pgc)
+ {
+ hb_error( "scan: pgc not valid, skipping" );
+ break;
+ }
+ duration += 90LL * dvdtime2msec( &pgc->playback_time );
+
+ cell_start = pgc->program_map[pgn-1] - 1;
+ cell_end = pgc->nr_of_cells - 1;
+ for(i = cell_start; i <= cell_end; i = FindNextCell(pgc, i))
+ {
+ *blocks += pgc->cell_playback[i].last_sector + 1 -
+ pgc->cell_playback[i].first_sector;
+ }
+ *last_pgcn = pgcn;
+ pgn = 1;
+ } while((pgcn = NextPgcn(ifo, pgcn)) != 0);
+ return duration;
+}
+
/***********************************************************************
* hb_dvdnav_title_scan
**********************************************************************/
@@ -218,13 +269,15 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
hb_dvdnav_t * d = &(e->dvdnav);
hb_title_t * title;
- ifo_handle_t * vts = NULL;
- int pgc_id, pgn, i;
+ ifo_handle_t * ifo = NULL;
+ int pgcn, pgn, pgcn_end, i, c;
+ int title_pgcn;
pgc_t * pgc;
int cell_cur;
hb_chapter_t * chapter;
- int c;
- uint64_t duration;
+ int count;
+ uint64_t duration, longest;
+ int longest_pgcn, longest_pgn, longest_pgcn_end;
float duration_correction;
const char * name;
@@ -259,7 +312,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
}
hb_log( "scan: opening IFO for VTS %d", title->vts );
- if( !( vts = ifoOpen( d->reader, title->vts ) ) )
+ if( !( ifo = ifoOpen( d->reader, title->vts ) ) )
{
hb_error( "scan: ifoOpen failed" );
goto fail;
@@ -267,31 +320,31 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
/* ignore titles with bogus cell addresses so we don't abort later
** in libdvdread. */
- for ( i = 0; i < vts->vts_c_adt->nr_of_vobs; ++i)
+ for ( i = 0; i < ifo->vts_c_adt->nr_of_vobs; ++i)
{
- if( (vts->vts_c_adt->cell_adr_table[i].start_sector & 0xffffff ) ==
+ if( (ifo->vts_c_adt->cell_adr_table[i].start_sector & 0xffffff ) ==
0xffffff )
{
hb_error( "scan: cell_adr_table[%d].start_sector invalid (0x%x) "
"- skipping title", i,
- vts->vts_c_adt->cell_adr_table[i].start_sector );
+ ifo->vts_c_adt->cell_adr_table[i].start_sector );
goto fail;
}
- if( (vts->vts_c_adt->cell_adr_table[i].last_sector & 0xffffff ) ==
+ if( (ifo->vts_c_adt->cell_adr_table[i].last_sector & 0xffffff ) ==
0xffffff )
{
hb_error( "scan: cell_adr_table[%d].last_sector invalid (0x%x) "
"- skipping title", i,
- vts->vts_c_adt->cell_adr_table[i].last_sector );
+ ifo->vts_c_adt->cell_adr_table[i].last_sector );
goto fail;
}
- if( vts->vts_c_adt->cell_adr_table[i].start_sector >=
- vts->vts_c_adt->cell_adr_table[i].last_sector )
+ if( ifo->vts_c_adt->cell_adr_table[i].start_sector >=
+ ifo->vts_c_adt->cell_adr_table[i].last_sector )
{
hb_error( "scan: cell_adr_table[%d].start_sector (0x%x) "
"is not before last_sector (0x%x) - skipping title", i,
- vts->vts_c_adt->cell_adr_table[i].start_sector,
- vts->vts_c_adt->cell_adr_table[i].last_sector );
+ ifo->vts_c_adt->cell_adr_table[i].start_sector,
+ ifo->vts_c_adt->cell_adr_table[i].last_sector );
goto fail;
}
}
@@ -303,55 +356,74 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
/* Position of the title in the VTS */
title->ttn = d->vmg->tt_srpt->title[t-1].vts_ttn;
- if ( title->ttn < 1 || title->ttn > vts->vts_ptt_srpt->nr_of_srpts )
+ if ( title->ttn < 1 || title->ttn > ifo->vts_ptt_srpt->nr_of_srpts )
{
hb_error( "invalid VTS PTT offset %d for title %d, skipping", title->ttn, t );
goto fail;
}
-
- /* Get pgc */
- pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgcn;
- if ( pgc_id < 1 || pgc_id > vts->vts_pgcit->nr_of_pgci_srp )
+ longest = 0LL;
+ longest_pgcn = -1;
+ longest_pgn = 1;
+ longest_pgcn_end = -1;
+ pgcn_end = -1;
+ for( i = 0; i < ifo->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts; i++ )
{
- hb_error( "invalid PGC ID %d for title %d, skipping", pgc_id, t );
- goto fail;
- }
- pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgn;
- pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc;
+ int blocks = 0;
- hb_log("pgc_id: %d, pgn: %d: pgc: 0x%x", pgc_id, pgn, pgc);
+ duration = PttDuration(ifo, title->ttn, i+1, &blocks, &pgcn_end);
+ pgcn = ifo->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgcn;
+ pgn = ifo->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgn;
+ if( duration > longest )
+ {
+ longest_pgcn = pgcn;
+ longest_pgn = pgn;
+ longest_pgcn_end = pgcn_end;
+ longest = duration;
+ title->block_count = blocks;
+ }
+ else if (pgcn == longest_pgcn && pgn < longest_pgn)
+ {
+ longest_pgn = pgn;
+ title->block_count = blocks;
+ }
+ }
- if( !pgc )
+ /* ignore titles under 10 seconds because they're often stills or
+ * clips with no audio & our preview code doesn't currently handle
+ * either of these. */
+ if( longest < 900000LL )
{
- hb_error( "scan: pgc not valid, skipping" );
+ hb_log( "scan: ignoring title (too short)" );
goto fail;
}
- if( pgn <= 0 || pgn > 99 )
+ pgcn = longest_pgcn;
+ pgcn_end = longest_pgcn_end;
+ pgn = longest_pgn;;
+ title_pgcn = pgcn;
+
+
+ /* Get pgc */
+ if ( pgcn < 1 || pgcn > ifo->vts_pgcit->nr_of_pgci_srp )
{
- hb_error( "scan: pgn %d not valid, skipping", pgn );
+ hb_error( "invalid PGC ID %d for title %d, skipping", pgcn, t );
goto fail;
}
- /* Start cell */
- title->cell_start = pgc->program_map[pgn-1] - 1;
+ pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
+
+ hb_log("pgc_id: %d, pgn: %d: pgc: 0x%x", pgcn, pgn, pgc);
+
+ /* Title start */
+ title->cell_start = pgc->program_map[pgn-1] - 1;
title->block_start = pgc->cell_playback[title->cell_start].first_sector;
- /* End cell */
- title->cell_end = pgc->nr_of_cells - 1;
- title->block_end = pgc->cell_playback[title->cell_end].last_sector;
+ pgc = ifo->vts_pgcit->pgci_srp[pgcn_end-1].pgc;
- /* Block count */
- title->block_count = 0;
- cell_cur = title->cell_start;
- while( cell_cur <= title->cell_end )
- {
-#define cp pgc->cell_playback[cell_cur]
- title->block_count += cp.last_sector + 1 - cp.first_sector;
-#undef cp
- cell_cur = FindNextCell( pgc, cell_cur );
- }
+ /* Title end */
+ title->cell_end = pgc->nr_of_cells - 1;
+ title->block_end = pgc->cell_playback[title->cell_end].last_sector;
hb_log( "scan: vts=%d, ttn=%d, cells=%d->%d, blocks=%d->%d, "
"%d blocks", title->vts, title->ttn, title->cell_start,
@@ -359,7 +431,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
title->block_count );
/* Get duration */
- title->duration = 90LL * dvdtime2msec( &pgc->playback_time );
+ title->duration = longest;
title->hours = title->duration / 90000 / 3600;
title->minutes = ( ( title->duration / 90000 ) % 3600 ) / 60;
title->seconds = ( title->duration / 90000 ) % 60;
@@ -367,17 +439,8 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
title->hours, title->minutes, title->seconds,
title->duration / 90 );
- /* ignore titles under 10 seconds because they're often stills or
- * clips with no audio & our preview code doesn't currently handle
- * either of these. */
- if( title->duration < 900000LL )
- {
- hb_log( "scan: ignoring title (too short)" );
- goto fail;
- }
-
/* Detect languages */
- for( i = 0; i < vts->vtsi_mat->nr_of_vts_audio_streams; i++ )
+ for( i = 0; i < ifo->vtsi_mat->nr_of_vts_audio_streams; i++ )
{
hb_audio_t * audio, * audio_tmp;
int audio_format, lang_code, audio_control,
@@ -389,11 +452,11 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
audio = calloc( sizeof( hb_audio_t ), 1 );
- audio_format = vts->vtsi_mat->vts_audio_attr[i].audio_format;
- lang_code = vts->vtsi_mat->vts_audio_attr[i].lang_code;
- lang_extension = vts->vtsi_mat->vts_audio_attr[i].code_extension;
+ audio_format = ifo->vtsi_mat->vts_audio_attr[i].audio_format;
+ lang_code = ifo->vtsi_mat->vts_audio_attr[i].lang_code;
+ lang_extension = ifo->vtsi_mat->vts_audio_attr[i].code_extension;
audio_control =
- vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i];
+ ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->audio_control[i];
if( !( audio_control & 0x8000 ) )
{
@@ -459,7 +522,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
audio->config.lang.type = lang_extension;
- lang = lang_for_code( vts->vtsi_mat->vts_audio_attr[i].lang_code );
+ lang = lang_for_code( ifo->vtsi_mat->vts_audio_attr[i].lang_code );
snprintf( audio->config.lang.description, sizeof( audio->config.lang.description ), "%s (%s)",
strlen(lang->native_name) ? lang->native_name : lang->eng_name,
@@ -504,11 +567,11 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
}
memcpy( title->palette,
- vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->palette,
+ ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->palette,
16 * sizeof( uint32_t ) );
/* Check for subtitles */
- for( i = 0; i < vts->vtsi_mat->nr_of_vts_subp_streams; i++ )
+ for( i = 0; i < ifo->vtsi_mat->nr_of_vts_subp_streams; i++ )
{
hb_subtitle_t * subtitle;
int spu_control;
@@ -519,7 +582,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
hb_log( "scan: checking subtitle %d", i + 1 );
spu_control =
- vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i];
+ ifo->vts_pgcit->pgci_srp[title_pgcn-1].pgc->subp_control[i];
if( !( spu_control & 0x80000000 ) )
{
@@ -527,9 +590,9 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
continue;
}
- if( vts->vtsi_mat->vts_video_attr.display_aspect_ratio )
+ if( ifo->vtsi_mat->vts_video_attr.display_aspect_ratio )
{
- switch( vts->vtsi_mat->vts_video_attr.permitted_df )
+ switch( ifo->vtsi_mat->vts_video_attr.permitted_df )
{
case 1:
position = spu_control & 0xFF;
@@ -546,9 +609,9 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
position = ( spu_control >> 24 ) & 0x7F;
}
- lang_extension = vts->vtsi_mat->vts_subp_attr[i].code_extension;
+ lang_extension = ifo->vtsi_mat->vts_subp_attr[i].code_extension;
- lang = lang_for_code( vts->vtsi_mat->vts_subp_attr[i].lang_code );
+ lang = lang_for_code( ifo->vtsi_mat->vts_subp_attr[i].lang_code );
subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd;
@@ -612,36 +675,66 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
}
/* Chapters */
- hb_log( "scan: title %d has %d chapters", t,
- vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts );
- for( i = 0, c = 1;
- i < vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts; i++ )
+ PgcWalkInit();
+ c = 0;
+ do
+ {
+ pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
+
+ for (i = pgn; i <= pgc->nr_of_programs; i++)
+ {
+ chapter = calloc( sizeof( hb_chapter_t ), 1 );
+
+ chapter->index = c + 1;
+ chapter->pgcn = pgcn;
+ chapter->pgn = i;
+ hb_list_add( title->list_chapter, chapter );
+ c++;
+ }
+
+ pgn = 1;
+ } while ((pgcn = NextPgcn(ifo, pgcn)) != 0);
+
+ hb_log( "scan: title %d has %d chapters", t, c );
+
+ duration = 0;
+ count = hb_list_count( title->list_chapter );
+ for (i = 0; i < count; i++)
{
- int pgc_id_next, pgn_next;
+ int pgcn_next, pgn_next;
pgc_t * pgc_next;
+ hb_chapter_t *chapter_next;
+ int pgc_cell_end;
- chapter = calloc( sizeof( hb_chapter_t ), 1 );
- /* remember the on-disc chapter number */
- chapter->index = i + 1;
+ chapter = hb_list_item( title->list_chapter, i );
- pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgcn;
- pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgn;
- pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc;
+ pgcn = chapter->pgcn;
+ pgn = chapter->pgn;
+ pgc = ifo->vts_pgcit->pgci_srp[pgcn-1].pgc;
/* 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 != vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts - 1 )
+ if( i < count - 1 )
{
/* The cell before the starting cell of the next chapter,
or... */
- pgc_id_next = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i+1].pgcn;
- pgn_next = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i+1].pgn;
- pgc_next = vts->vts_pgcit->pgci_srp[pgc_id_next-1].pgc;
- chapter->cell_end = pgc_next->program_map[pgn_next-1] - 2;
+ 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? */
@@ -652,15 +745,12 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
else
{
/* ... the last cell of the title */
- chapter->cell_end = title->cell_end;
+ chapter->cell_end = pgc_cell_end;
}
chapter->block_end =
pgc->cell_playback[chapter->cell_end].last_sector;
/* Block count, duration */
- pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgcn;
- pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgn;
- pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc;
chapter->block_count = 0;
chapter->duration = 0;
@@ -673,18 +763,11 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
#undef cp
cell_cur = FindNextCell( pgc, cell_cur );
}
- hb_list_add( title->list_chapter, chapter );
- c++;
+ duration += chapter->duration;
}
/* The durations we get for chapters aren't precise. Scale them so
the total matches the title duration */
- duration = 0;
- for( i = 0; i < hb_list_count( title->list_chapter ); i++ )
- {
- chapter = hb_list_item( title->list_chapter, i );
- duration += chapter->duration;
- }
duration_correction = (float) title->duration / (float) duration;
for( i = 0; i < hb_list_count( title->list_chapter ); i++ )
{
@@ -704,7 +787,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
/* Get aspect. We don't get width/height/rate infos here as
they tend to be wrong */
- switch( vts->vtsi_mat->vts_video_attr.display_aspect_ratio )
+ switch( ifo->vtsi_mat->vts_video_attr.display_aspect_ratio )
{
case 0:
title->container_aspect = 4. / 3.;
@@ -728,7 +811,7 @@ fail:
title = NULL;
cleanup:
- if( vts ) ifoClose( vts );
+ if( ifo ) ifoClose( ifo );
return title;
}
@@ -738,53 +821,33 @@ cleanup:
***********************************************************************
* Title and chapter start at 1
**********************************************************************/
-static int hb_dvdnav_start( hb_dvd_t * e, int title, int chapter )
+static int hb_dvdnav_start( hb_dvd_t * e, hb_title_t *title, int c )
{
hb_dvdnav_t * d = &(e->dvdnav);
- ifo_handle_t *ifo;
- int ii;
- int vts, ttn, pgc_id, pgn;
- pgc_t *pgc;
- int cell_start, cell_end, title_start, title_end;
-
- vts = d->vmg->tt_srpt->title[title-1].title_set_nr;
- ttn = d->vmg->tt_srpt->title[title-1].vts_ttn;
- if( !( ifo = ifoOpen( d->reader, vts ) ) )
- {
- hb_error( "dvd: ifoOpen failed for VTS %d", vts );
- return 0;
- }
+ int t = title->index;
+ hb_chapter_t *chapter;
+ dvdnav_status_t result;
- /* Get title first and last blocks */
- pgc_id = ifo->vts_ptt_srpt->title[ttn-1].ptt[0].pgcn;
- pgn = ifo->vts_ptt_srpt->title[ttn-1].ptt[0].pgn;
- pgc = ifo->vts_pgcit->pgci_srp[pgc_id-1].pgc;
- cell_start = pgc->program_map[pgn - 1] - 1;
- cell_end = pgc->nr_of_cells - 1;
- title_start = pgc->cell_playback[cell_start].first_sector;
- title_end = pgc->cell_playback[cell_end].last_sector;
-
- /* Block count */
- d->title_block_count = 0;
- for( ii = cell_start; ii <= cell_end; ii++ )
- {
- d->title_block_count += pgc->cell_playback[ii].last_sector + 1 -
- pgc->cell_playback[ii].first_sector;
- }
- ifoClose(ifo);
+ d->title_block_count = title->block_count;
+ d->list_chapter = title->list_chapter;
- if ( d->stopped && !hb_dvdnav_reset(d) )
+ if ( d->stopped && !hb_dvdnav_reset(d) )
{
return 0;
}
- if ( dvdnav_part_play(d->dvdnav, title, chapter) != DVDNAV_STATUS_OK )
+ chapter = hb_list_item( title->list_chapter, c - 1);
+ if (chapter != NULL)
+ result = dvdnav_program_play(d->dvdnav, t, chapter->pgcn, chapter->pgn);
+ else
+ result = dvdnav_part_play(d->dvdnav, t, 1);
+ if (result != DVDNAV_STATUS_OK)
{
- hb_error( "dvd: dvdnav_title_play failed - %s",
+ hb_error( "dvd: dvdnav_*_play failed - %s",
dvdnav_err_to_string(d->dvdnav) );
return 0;
}
- d->title = title;
- d->stopped = 0;
+ d->title = t;
+ d->stopped = 0;
return 1;
}
@@ -795,7 +858,6 @@ static int hb_dvdnav_start( hb_dvd_t * e, int title, int chapter )
**********************************************************************/
static void hb_dvdnav_stop( hb_dvd_t * e )
{
- hb_dvdnav_t * d = &(e->dvdnav);
}
/***********************************************************************
@@ -812,9 +874,10 @@ static int hb_dvdnav_seek( hb_dvd_t * e, float f )
int done = 0, ii;
if (d->stopped)
- {
- return 0;
- }
+ {
+ return 0;
+ }
+
// 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
@@ -842,7 +905,8 @@ static int hb_dvdnav_seek( hb_dvd_t * e, float f )
break;
case DVDNAV_STOP:
- d->stopped = 1;
+ hb_log("dvdnav: stop encountered during seek");
+ d->stopped = 1;
return 0;
case DVDNAV_HOP_CHANNEL:
@@ -881,10 +945,10 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b )
while ( 1 )
{
- if (d->stopped)
- {
- return 0;
- }
+ if (d->stopped)
+ {
+ return 0;
+ }
result = dvdnav_get_next_block( d->dvdnav, b->data, &event, &len );
if ( result == DVDNAV_STATUS_ERR )
{
@@ -980,16 +1044,17 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b )
* and update the decoding/displaying accordingly.
*/
{
- int tt = 0, ptt = 0;
+ int tt = 0, pgcn = 0, pgn = 0, c;
- dvdnav_current_title_info(d->dvdnav, &tt, &ptt);
+ dvdnav_current_title_program(d->dvdnav, &tt, &pgcn, &pgn);
if (tt != d->title)
{
// Transition to another title signals that we are done.
return 0;
}
- if (ptt > d->chapter)
- chapter = d->chapter = ptt;
+ c = FindChapterIndex(d->list_chapter, pgcn, pgn);
+ if (c > d->chapter)
+ chapter = d->chapter = c;
}
break;
@@ -1027,7 +1092,7 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b )
/*
* Playback should end here.
*/
- d->stopped = 1;
+ d->stopped = 1;
return 0;
default:
@@ -1046,12 +1111,14 @@ static int hb_dvdnav_read( hb_dvd_t * e, hb_buffer_t * b )
static int hb_dvdnav_chapter( hb_dvd_t * e )
{
hb_dvdnav_t * d = &(e->dvdnav);
- int32_t t, c;
+ int32_t t, pgcn, pgn;
+ int32_t c;
- if (dvdnav_current_title_info(d->dvdnav, &t, &c) != DVDNAV_STATUS_OK)
+ if (dvdnav_current_title_program(d->dvdnav, &t, &pgcn, &pgn) != DVDNAV_STATUS_OK)
{
return -1;
}
+ c = FindChapterIndex( d->list_chapter, pgcn, pgn );
return c;
}
@@ -1106,6 +1173,27 @@ static void hb_dvdnav_set_angle( hb_dvd_t * e, int angle )
}
/***********************************************************************
+ * FindChapterIndex
+ ***********************************************************************
+ * 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.
+ **********************************************************************/
+static int FindChapterIndex( hb_list_t * list, int pgcn, int pgn )
+{
+ int count, ii;
+ hb_chapter_t *chapter;
+
+ count = hb_list_count( list );
+ for (ii = 0; ii < count; ii++)
+ {
+ chapter = hb_list_item( list, ii );
+ if (chapter->pgcn == pgcn && chapter->pgn == pgn)
+ return chapter->index;
+ }
+ return 0;
+}
+
+/***********************************************************************
* FindNextCell
***********************************************************************
* Assumes pgc and cell_cur are correctly set, and sets cell_next to the
@@ -1137,6 +1225,49 @@ 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.
+ **********************************************************************/
+static int NextPgcn( ifo_handle_t *ifo, int pgcn )
+{
+ int byte;
+ uint8_t bit;
+ int next_pgcn;
+ pgc_t *pgc;
+
+ byte = pgcn >> 3;
+ bit = 1 << (pgcn & 0x7);
+ pgcn_map[byte] |= bit;
+
+ 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;
+}
+
+/***********************************************************************
+ * PgcWalkInit
+ ***********************************************************************
+ * Pgc links can loop. I track which have been visited in a bit vector
+ * Initialize the bit vector to empty.
+ **********************************************************************/
+static void PgcWalkInit( void )
+{
+ memset(pgcn_map, 0, 128);
+}
+
/***********************************************************************
* dvdtime2msec
***********************************************************************
diff --git a/libhb/internal.h b/libhb/internal.h
index 8d927501c..7d7594802 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -174,7 +174,7 @@ typedef struct hb_stream_s hb_stream_t;
hb_dvd_t * hb_dvd_init( char * path );
int hb_dvd_title_count( hb_dvd_t * );
hb_title_t * hb_dvd_title_scan( hb_dvd_t *, int title );
-int hb_dvd_start( hb_dvd_t *, int title, int chapter );
+int hb_dvd_start( hb_dvd_t *, hb_title_t *title, int chapter );
void hb_dvd_stop( hb_dvd_t * );
int hb_dvd_seek( hb_dvd_t *, float );
int hb_dvd_read( hb_dvd_t *, hb_buffer_t * );
diff --git a/libhb/reader.c b/libhb/reader.c
index 78f24a457..0acbe0921 100644
--- a/libhb/reader.c
+++ b/libhb/reader.c
@@ -220,7 +220,7 @@ static void ReaderFunc( void * _r )
}
/* end chapter mapping XXX */
- if( !hb_dvd_start( r->dvd, r->title->index, start ) )
+ if( !hb_dvd_start( r->dvd, r->title, start ) )
{
hb_dvd_close( &r->dvd );
return;
diff --git a/libhb/scan.c b/libhb/scan.c
index db179ef75..a549285b5 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -407,7 +407,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
if (data->dvd)
{
- hb_dvd_start( data->dvd, title->index, 1 );
+ hb_dvd_start( data->dvd, title, 1 );
title->angle_count = hb_dvd_angle_count( data->dvd );
hb_log( "scan: title angle(s) %d", title->angle_count );
}