#include "dvd.h"
#include "dvdread/ifo_read.h"
+#include "dvdread/ifo_print.h"
#include "dvdread/nav_read.h"
static hb_dvd_t * hb_dvdread_init( char * path );
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 hb_title_t * hb_dvdread_title_scan( hb_dvd_t * d, int t, uint64_t min_duration );
+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 );
static int hb_dvdread_chapter( hb_dvd_t * d );
static int hb_dvdread_angle_count( hb_dvd_t * d );
static void hb_dvdread_set_angle( hb_dvd_t * d, int angle );
+static int hb_dvdread_main_feature( hb_dvd_t * d, hb_list_t * list_title );
hb_dvd_func_t hb_dvdread_func =
{
hb_dvdread_read,
hb_dvdread_chapter,
hb_dvdread_angle_count,
- hb_dvdread_set_angle
+ hb_dvdread_set_angle,
+ hb_dvdread_main_feature
};
static hb_dvd_func_t *dvd_methods = &hb_dvdread_func;
return &hb_dvdread_func;
}
+static int hb_dvdread_main_feature( hb_dvd_t * e, hb_list_t * list_title )
+{
+ int ii;
+ uint64_t longest_duration = 0;
+ int longest = -1;
+
+ for ( ii = 0; ii < hb_list_count( list_title ); ii++ )
+ {
+ hb_title_t * title = hb_list_item( list_title, ii );
+ if ( title->duration > longest_duration )
+ {
+ longest_duration = title->duration;
+ longest = title->index;
+ }
+ }
+ return longest;
+}
+
static char * hb_dvdread_name( char * path )
{
static char name[1024];
{
hb_dvd_t * e;
hb_dvdread_t * d;
+ int region_mask;
e = calloc( sizeof( hb_dvd_t ), 1 );
d = &(e->dvdread);
+ /* Log DVD drive region code */
+ if ( hb_dvd_region( path, ®ion_mask ) == 0 )
+ {
+ hb_log( "dvd: Region mask 0x%02x", region_mask );
+ if ( region_mask == 0xFF )
+ {
+ hb_log( "dvd: Warning, DVD device has no region set" );
+ }
+ }
+
/* Open device */
if( !( d->reader = DVDOpen( path ) ) )
{
/***********************************************************************
* hb_dvdread_title_scan
**********************************************************************/
-static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t )
+static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_duration )
{
hb_dvdread_t *d = &(e->dvdread);
hb_log( "scan: scanning title %d", t );
title = hb_title_init( d->path, t );
+ title->type = HB_DVD_TYPE;
+
if( DVDUDFVolumeInfo( d->reader, title->name, sizeof( title->name ),
unused, sizeof( unused ) ) )
{
pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgn;
d->pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc;
- hb_log("pgc_id: %d, pgn: %d: pgc: 0x%x", pgc_id, pgn, d->pgc);
+ hb_log("pgc_id: %d, pgn: %d: pgc: %p", pgc_id, pgn, d->pgc);
if( !d->pgc )
{
d->cell_cur = d->cell_next;
}
- hb_log( "scan: vts=%d, ttn=%d, cells=%d->%d, blocks=%d->%d, "
- "%d blocks", title->vts, title->ttn, title->cell_start,
+ hb_log( "scan: vts=%d, ttn=%d, cells=%d->%d, blocks=%"PRIu64"->%"PRIu64", "
+ "%"PRIu64" blocks", title->vts, title->ttn, title->cell_start,
title->cell_end, title->block_start, title->block_end,
title->block_count );
title->hours = title->duration / 90000 / 3600;
title->minutes = ( ( title->duration / 90000 ) % 3600 ) / 60;
title->seconds = ( title->duration / 90000 ) % 60;
- hb_log( "scan: duration is %02d:%02d:%02d (%lld ms)",
+ hb_log( "scan: duration is %02d:%02d:%02d (%"PRId64" ms)",
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 )
+ if( title->duration < min_duration )
{
hb_log( "scan: ignoring title (too short)" );
goto fail;
hb_list_add( title->list_audio, audio );
}
- if( !hb_list_count( title->list_audio ) )
- {
- hb_log( "scan: ignoring title (no audio track)" );
- goto fail;
- }
-
- memcpy( title->palette,
- vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->palette,
- 16 * sizeof( uint32_t ) );
-
/* Check for subtitles */
for( i = 0; i < vts->vtsi_mat->nr_of_vts_subp_streams; i++ )
{
lang = lang_for_code( vts->vtsi_mat->vts_subp_attr[i].lang_code );
subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
+ subtitle->track = i+1;
subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd;
snprintf( subtitle->lang, sizeof( subtitle->lang ), "%s",
strlen(lang->native_name) ? lang->native_name : lang->eng_name);
snprintf( subtitle->iso639_2, sizeof( subtitle->iso639_2 ), "%s",
lang->iso639_2);
+ subtitle->format = PICTURESUB;
+ subtitle->source = VOBSUB;
+ subtitle->config.dest = RENDERSUB; // By default render (burn-in) the VOBSUB.
subtitle->type = lang_extension;
+
+ memcpy( subtitle->palette,
+ vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->palette,
+ 16 * sizeof( uint32_t ) );
switch( lang_extension )
{
for( i = 0, c = 1;
i < vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts; i++ )
{
- int pgc_id_next, pgn_next;
- pgc_t * pgc_next;
-
chapter = calloc( sizeof( hb_chapter_t ), 1 );
/* remember the on-disc chapter number */
chapter->index = i + 1;
chapter->block_start =
d->pgc->cell_playback[chapter->cell_start].first_sector;
- /* End cell */
- if( i != vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts - 1 )
+ // 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 == d->pgc->nr_of_programs )
{
- /* 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;
- if( chapter->cell_end < 0 )
- {
- /* Huh? */
- free( chapter );
- continue;
- }
+ chapter->cell_end = d->pgc->nr_of_cells - 1;
}
else
{
- /* ... the last cell of the title */
- chapter->cell_end = title->cell_end;
+ chapter->cell_end = d->pgc->program_map[pgn] - 2;;
}
- chapter->block_end =
- d->pgc->cell_playback[chapter->cell_end].last_sector;
+ chapter->block_end = d->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;
- d->pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc;
chapter->block_count = 0;
chapter->duration = 0;
chapter->minutes = ( seconds % 3600 ) / 60;
chapter->seconds = seconds % 60;
- hb_log( "scan: chap %d c=%d->%d, b=%d->%d (%d), %lld ms",
+ hb_log( "scan: chap %d c=%d->%d, b=%"PRIu64"->%"PRIu64" (%"PRIu64"), %"PRId64" ms",
chapter->index, chapter->cell_start, chapter->cell_end,
chapter->block_start, chapter->block_end,
chapter->block_count, chapter->duration / 90 );
***********************************************************************
* 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 );
{
int block, pack_len, next_vobu, read_retry;
- for( read_retry = 0; read_retry < 3; read_retry++ )
+ for( read_retry = 1; read_retry < 1024; read_retry++ )
{
if( DVDReadBlocks( d->file, d->next_vobu, 1, b->data ) == 1 )
{
/*
* Successful read.
*/
+ if( read_retry > 1 && !is_nav_pack( b->data) )
+ {
+ // But wasn't a nav pack, so carry on looking
+ read_retry = 1;
+ d->next_vobu++;
+ continue;
+ }
break;
- } else {
- hb_log( "dvd: Read Error on blk %d, attempt %d",
- d->next_vobu, read_retry );
+ } else {
+ // First retry the same block, then try the next one,
+ // adjust the skip increment upwards so that we can skip
+ // large sections of bad blocks more efficiently (at the
+ // cost of some missed good blocks at the end).
+ hb_log( "dvd: vobu read error blk %d - skipping to next blk incr %d",
+ d->next_vobu, (read_retry * 10));
+ d->next_vobu += (read_retry * 10);
}
+
}
- if( read_retry == 3 )
+ if( read_retry == 1024 )
{
+ // That's too many bad blocks, jump to the start of the
+ // next cell.
hb_log( "dvd: vobu read error blk %d - skipping to cell %d",
d->next_vobu, d->cell_next );
d->cell_cur = d->cell_next;
hb_log("dvd: Lost sync, searching for NAV pack at blk %d",
d->next_vobu);
d->in_sync = 0;
- }
+ }
continue;
}
}
if( d->in_cell )
{
- hb_error( "dvd: assuming missed end of cell %d", d->cell_cur );
+ hb_error( "dvd: assuming missed end of cell %d at block %d", d->cell_cur, d->block );
d->cell_cur = d->cell_next;
d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector;
FindNextCell( d );
return dvd_methods->title_count(d);
}
-hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
+hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t, uint64_t min_duration )
{
- return dvd_methods->title_scan(d, t);
+ return dvd_methods->title_scan(d, t, min_duration);
}
-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);
}
dvd_methods->set_angle(d, angle);
}
+int hb_dvd_main_feature( hb_dvd_t * d, hb_list_t * list_title )
+{
+ return dvd_methods->main_feature(d, list_title);
+}
+
// hb_dvd_set_dvdnav must only be called when no dvd source is open
// it rips the rug out from under things so be careful
void hb_dvd_set_dvdnav( int enable )