From c13cdcac1fff0055891bb3fc333db4803dee3b64 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sun, 28 Feb 2010 14:19:47 +0100 Subject: [PATCH 1/2] Add the -s option to skip sections of unreadable sectors faster. Don't retry in case of failed reads. Write dummy blocks to keep the position of readable blocks unchanged. Scale the number of blocks that are skipped automatically. --- vobcopy.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 97 insertions(+), 24 deletions(-) diff --git a/vobcopy.c b/vobcopy.c index 1a0f8b6..293c966 100644 --- a/vobcopy.c +++ b/vobcopy.c @@ -58,6 +58,48 @@ bool overwrite_flag = FALSE; bool overwrite_all_flag = FALSE; int overall_skipped_blocks = 0; +static int get_number_of_blocks_to_skip(dvd_file_t *dvd_file, int original_offset) +{ + unsigned char bufferin[DVD_VIDEO_LB_LEN * BLOCK_COUNT]; + int blocks; + int offset; + /* + * Static so we use the last working value when called more than once. + * The initial value seems to be a reasonable guess but maybe it should be + * configurable. + */ + static int blocks_to_skip = 64; + + blocks_to_skip /= 2; + + do + { + blocks_to_skip *= 2; + fprintf( stderr, _("Reading block %d failed, trying block %d, blocks skipped %d\n"), + offset, original_offset + blocks_to_skip, blocks_to_skip); + offset = original_offset + blocks_to_skip; + } while ((blocks = DVDReadBlocks(dvd_file, offset, 1, bufferin)) <= 0); + + fprintf( stderr, _("Got a valid block at offset %d, after skipping %d. Trying to reduce the skipped blocks\n"), + offset, blocks_to_skip); + + do + { + /* + * XXX: This could be done smarter, for example by using a binary search. + */ + blocks_to_skip--; + offset = original_offset + blocks_to_skip; + } + while (blocks_to_skip > 0 && (blocks = DVDReadBlocks(dvd_file, offset, 1, bufferin)) > 0); + + fprintf( stderr, _("Got an ivalid block at offset %d, after skipping %d. Returning %d\n"), + offset, blocks_to_skip, blocks_to_skip +1); + + return blocks_to_skip + 1; +} + + /* --------------------------------------------------------------------------*/ /* MAIN */ /* --------------------------------------------------------------------------*/ @@ -92,6 +134,7 @@ and potentially fatal." - Thanks Leigh!*/ bool stdout_flag = FALSE, space_greater_2gb_flag = TRUE; bool fast_switch = FALSE, onefile_flag = FALSE; bool quiet_flag = FALSE, longest_title_flag = FALSE; + bool skip_invalid_blocks_flag = FALSE; struct stat buf; float lastpos = 0; int starttime; @@ -152,6 +195,7 @@ and potentially fatal." - Thanks Leigh!*/ {"version", 0, 0, 'V'}, {"watchdog", 1, 0, 'w'}, {"overwrite-all", 0, 0, 'x'}, + {"skip-invalid-blocks", 0, 0, 's'}, {0, 0, 0, 0} }; #endif @@ -173,10 +217,10 @@ and potentially fatal." - Thanks Leigh!*/ { #ifdef HAVE_GETOPT_LONG options_char = getopt_long( argc, argv, - "1:2:3:4:a:b:c:e:i:n:o:qO:t:vfF:lmMhL:Vw:Ix", + "1:2:3:4:a:b:c:e:i:n:o:qO:s:t:vfF:lmMhL:Vw:Ix", long_options ,&option_index); #else - options_char = getopt( argc, argv, "1:2:3:4:a:b:c:e:i:n:o:qO:t:vfF:lmMhL:Vw:Ix-" ); + options_char = getopt( argc, argv, "1:2:3:4:a:b:c:e:i:n:o:qO:s:t:vfF:lmMhL:Vw:Ix-" ); #endif if ( options_char == -1 ) break; @@ -369,6 +413,10 @@ and potentially fatal." - Thanks Leigh!*/ /* force_flag = TRUE; */ break; + case 's': /* skip invalid blocks */ + skip_invalid_blocks_flag = TRUE; + break; + case'q':/*quiet flag* - meaning no progress and such output*/ quiet_flag = TRUE; break; @@ -1311,7 +1359,10 @@ next: /*for the goto - ugly, I know... */ starttime = time(NULL); for( i = start; ( i - start ) * DVD_VIDEO_LB_LEN < file_size; i += file_block_count) { - int tries = 0, skipped_blocks = 0; + int tries = 0; + int skip_step = 0; + unsigned skipped_blocks = 0; + /* Only read and write as many blocks as there are left in the file */ if ( ( i - start + file_block_count ) * DVD_VIDEO_LB_LEN > file_size ) { @@ -1320,29 +1371,50 @@ next: /*for the goto - ugly, I know... */ /* DVDReadBlocks( dvd_file, i, 1, bufferin );this has to be wrong with the 1 there...*/ - while( ( blocks = DVDReadBlocks( dvd_file, i, file_block_count, bufferin ) ) <= 0 && tries < 10 ) - { - if( tries == 9 ) - { - i += file_block_count; - skipped_blocks +=1; - overall_skipped_blocks +=1; - tries=0; - } - /* if( verbosity_level >= 1 ) - fprintf( stderr, _("[Warn] Had to skip %d blocks (reading block %d)! \n "), skipped_blocks, i ); */ - tries++; + while( ( blocks = DVDReadBlocks( dvd_file, i, file_block_count, bufferin ) ) <= 0) + { + if (!skip_invalid_blocks_flag) + { + if (tries == 9) + { + fprintf( stderr, "[Warn] Retry attempt for block %d are up. " + "Consider using the -s flag to skip invalid blocks faster.\n", i); + i++; + skipped_blocks++; + overall_skipped_blocks++; + tries = 0; + continue; + } + fprintf( stderr, "[Warn] Retrying to read block %d.\n", i); + tries++; + continue; + } + skip_step = get_number_of_blocks_to_skip(dvd_file, i); + i += skip_step; + skipped_blocks += skip_step; + if( verbosity_level >= 1 ) + { + fprintf( stderr, "[Warn] Had to skip %d blocks! Now reading at offset %d\n", skipped_blocks, i ); + } } - - if( verbosity_level >= 1 && skipped_blocks > 0 ) - fprintf( stderr, _("[Warn] Had to skip (couldn't read) %d blocks (before block %d)! \n "), skipped_blocks, i ); - -/*TODO: this skipping here writes too few bytes to the output */ - - if( write( streamout, bufferin, DVD_VIDEO_LB_LEN * blocks ) < 0 ) + if (skip_step > 0) { - fprintf( stderr, _("\n[Error] Error writing to %s \n"), output_file ); - fprintf( stderr, _("[Error] Error: %s, errno: %d \n"), strerror( errno ), errno ); + unsigned int dummy_blocks; + fprintf( stderr, "[Warn] Duplicating first readable block as dummy for the %d skipped ones\n", skipped_blocks ); + for (dummy_blocks = 0; dummy_blocks < skipped_blocks; dummy_blocks++) + { + if( write( streamout, bufferin, DVD_VIDEO_LB_LEN ) < 0 ) + { + fprintf( stderr, "\n[Error] Error writing dummy blocks to %s \n", output_file ); + fprintf( stderr, _("[Error] Error: %s, errno: %d \n"), strerror( errno ), errno ); + exit( 1 ); + } + } + } + if( write( streamout, bufferin, DVD_VIDEO_LB_LEN * blocks ) < 0 ) + { + fprintf( stderr, "\n[Error] Error writing to %s \n", output_file ); + fprintf( stderr, _("[Error] Error: %s, errno: %d \n"), strerror( errno ), errno ); exit( 1 ); } @@ -2098,6 +2170,7 @@ void usage( char *program_name ) fprintf( stderr, _("[-w ]\n" ) ); fprintf( stderr, _("[-x (overwrite all)]\n" ) ); fprintf( stderr, _("[-F ]\n") ); + fprintf( stderr, _("[-s (try to skip sections with invalid blocks faster, writing dummy blocks instead)]\n") ); #if defined( HAS_LARGEFILE ) || defined ( MAC_LARGEFILE ) fprintf( stderr, _("[-l (large-file support for files > 2GB)] \n") ); -- 1.7.5.2 From a3150847d2868a00cfdcab7e0e1e9c0bdc7a59bf Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Mon, 6 Jun 2011 19:33:11 +0200 Subject: [PATCH 2/2] Document the -s option --- vobcopy.1 | 12 +++++++++++- 1 files changed, 11 insertions(+), 1 deletions(-) diff --git a/vobcopy.1 b/vobcopy.1 index e3774ad..eabf81a 100644 --- a/vobcopy.1 +++ b/vobcopy.1 @@ -1,7 +1,7 @@ .\" Process this file with .\" groff -man -Tascii vobcopy.1 .\" -.TH VOBCOPY 1 "Jun 2009" Linux "User Manuals" +.TH VOBCOPY 1 "Jun 2011" Linux "User Manuals" .SH NAME vobcopy \- copy (rip) files from a dvd to the harddisk .SH SYNOPSIS @@ -79,6 +79,16 @@ mirrors the whole dvd to harddisk. It will create a directory named after the dv specify which title vobcopy shall copy (default is title with most chapters). On the dvd, vts_01_x.vob specify the first title (mostly this is the main feature). .IP "-o, --output-dir OUTPUT-DIR" specify the output-directory of the data. "stdout" or "-" redirect to stdout. Useful for pipeing it to /dev/null ;-) If you forget to pipe it to some place, your terminal will get garbled, so remember that typing "reset" and then Enter will rescue you. +.IP "-s" +try to skip sections of unreadable blocks faster. Lets vobcopy skip multiple blocks at the time +until a readable one is found at which point it goes back to find the first working block. +The number of blocks that are skipped is scaled automatically. +Skipped sections in the destination file are filled with dummy blocks to keep the readable blocks at the position +expected by the IFO files, therefore there's a fair chance that the menus for mirrored rips continue to work. +This option also disables vobcopy's internal retry mechanism. Performance may be further increased by +temporarily configuring the operating system to not retry failed reads for DVDs, either. +This option currently does not guarantee that all readable blocks will be ripped which +could be considered a bug. .IP "-q, --quiet" all info- and error-messages of vobcopy will end up in the current directory in vobcopy.bla instead of stderr .IP "-O, --onefile single_file(s)_to_rip" -- 1.7.5.2