I encountered a DVD that had a load of bad blocks near the start of the first chapter. Handbrake using dvdnav or dvdread fails to handle this gracefully and skips to the start of the next cell as a recovery, which skipped the majority of the first chapter in my case.
In this patch I have change the dvdread bad block recovery to scan forwards through the blocks whenever a read failure is encountered.
I also changed the number of consecutive failures in dvdnav (from 10 to 500) so that it at least skipped forwards when encountering bad blocks rather than aborting the encode.
Note that these changes work when reading direct from a DVD, however they didn't work with a pre-ripped copy of the same DVD since MTR bad a mess of the bad blocks, it wrote bad blocks write to the end of the cell.
http://paste.handbrake.fr/pastebin.php?show=1905
Code: Select all
Index: dvdnav.c
===================================================================
--- dvdnav.c (revision 3688)
+++ dvdnav.c (working copy)
@@ -1503,7 +1503,7 @@
return 0;
}
error_count++;
- if (error_count > 10)
+ if (error_count > 500)
{
hb_error("dvdnav: Error, too many consecutive read errors");
return 0;
Index: dvd.c
===================================================================
--- dvd.c (revision 3688)
+++ dvd.c (working copy)
@@ -861,22 +861,37 @@
{
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;
@@ -895,7 +910,7 @@
hb_log("dvd: Lost sync, searching for NAV pack at blk %d",
d->next_vobu);
d->in_sync = 0;
- }
+ }
continue;
}
@@ -1030,7 +1045,7 @@
}
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 );
Edit. I noticed that the comment is now incorrect regarding retrying the same block, I decided against that since it slows the whole process down, and anyway I'm sure the device driver is already doing retries when encountering issues.