+
+ // There are a total of 21 next vobu offsets (and 21 prev_vobu
+ // offsets) in the navpack SRI structure. The primary one is
+ // 'next_vobu' which is the offset (in dvd blocks) from the current
+ // block to the start of the next vobu. If the block at 'next_vobu'
+ // can't be read, 'next_video' is the offset to the vobu closest to it.
+ // The other 19 offsets are vobus at successively longer distances from
+ // the current block (this is so that a hardware player can do
+ // adaptive error recovery to skip over a bad spot on the disk). In all
+ // these offsets the high bit is set to indicate when it contains a
+ // valid offset. The next bit (2^30) is set to indicate that there's
+ // another valid offset in the SRI that's closer to the current block.
+ // A hardware player uses these bits to chose the closest valid offset
+ // and uses that as its next vobu. (Some mastering schemes appear to
+ // put a bogus offset in next_vobu with the 2^30 bit set & the
+ // correct offset in next_video. This works fine in hardware players
+ // but will mess up software that doesn't implement the full next
+ // vobu decision logic.) In addition to the flag bits there's a
+ // reserved value of the offset that indicates 'no next vobu' (which
+ // indicates the end of a cell). But having no next vobu pointer with a
+ // 'valid' bit set also indicates end of cell. Different mastering
+ // schemes seem to use all possible combinations of the flag bits
+ // and reserved values to indicate end of cell so we have to check
+ // them all or we'll get a disk read error from following an
+ // invalid offset.
+ uint32_t next_ptr = dsi_pack.vobu_sri.next_vobu;
+ if ( ( next_ptr & ( 1 << 31 ) ) == 0 ||
+ ( next_ptr & ( 1 << 30 ) ) != 0 ||
+ ( next_ptr & 0x3fffffff ) == 0x3fffffff )
+ {
+ next_ptr = dsi_pack.vobu_sri.next_video;
+ if ( ( next_ptr & ( 1 << 31 ) ) == 0 ||
+ ( next_ptr & 0x3fffffff ) == 0x3fffffff )
+ {
+ // don't have a valid forward pointer - assume end-of-cell
+ d->block = block;
+ d->pack_len = pack_len;
+ break;
+ }
+ }
+ next_vobu = block + ( next_ptr & 0x3fffffff );