OSDN Git Service

Getting rid of dvd open failure error, it is not an error when
[handbrake-jp/handbrake-jp-git.git] / libhb / dvd.c
index b26c559..3cfc1b9 100644 (file)
@@ -1,7 +1,7 @@
 /* $Id: dvd.c,v 1.12 2005/11/25 15:05:25 titer Exp $
 
    This file is part of the HandBrake source code.
-   Homepage: <http://handbrake.m0k.org/>.
+   Homepage: <http://handbrake.fr/>.
    It may be used under the terms of the GNU General Public License. */
 
 #include "hb.h"
@@ -34,6 +34,10 @@ struct hb_dvd_s
     int            block;
     int            pack_len;
     int            next_vobu;
+    int            in_cell;
+    int            in_sync;
+    uint16_t       cur_vob_id;
+    uint8_t        cur_cell_id;
 };
 
 /***********************************************************************
@@ -79,14 +83,17 @@ hb_dvd_t * hb_dvd_init( char * path )
     /* Open device */
     if( !( d->reader = DVDOpen( path ) ) )
     {
-        hb_log( "dvd: DVDOpen failed (%s)", path );
+        /*
+         * Not an error, may be a stream - which we'll try in a moment.
+         */
+        hb_log( "dvd: not a dvd - trying as a stream/file instead" );
         goto fail;
     }
 
     /* Open main IFO */
     if( !( d->vmg = ifoOpen( d->reader, 0 ) ) )
     {
-        hb_log( "dvd: ifoOpen failed" );
+        hb_error( "dvd: ifoOpen failed" );
         goto fail;
     }
 
@@ -118,7 +125,7 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
     hb_title_t   * title;
     ifo_handle_t * vts = NULL;
     int            pgc_id, pgn, i;
-    hb_chapter_t * chapter, * chapter_old;
+    hb_chapter_t * chapter;
     int            c;
     uint64_t       duration;
     float          duration_correction;
@@ -144,10 +151,17 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
     /* VTS which our title is in */
     title->vts = d->vmg->tt_srpt->title[t-1].title_set_nr;
 
+    if ( !title->vts )
+    {
+        /* A VTS of 0 means the title wasn't found in the title set */
+        hb_error("Invalid VTS (title set) number: %i", title->vts);
+        goto fail;
+    }
+
     hb_log( "scan: opening IFO for VTS %d", title->vts );
     if( !( vts = ifoOpen( d->reader, title->vts ) ) )
     {
-        hb_log( "scan: ifoOpen failed" );
+        hb_error( "scan: ifoOpen failed" );
         goto fail;
     }
 
@@ -159,6 +173,20 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
     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);
+
+    if( !d->pgc )
+    {
+        hb_error( "scan: pgc not valid, skipping" );
+        goto fail;
+    }
+
+    if( pgn <= 0 || pgn > 99 )
+    {
+        hb_error( "scan: pgn %d not valid, skipping", pgn );
+        goto fail;
+    }
+
     /* Start cell */
     title->cell_start  = d->pgc->program_map[pgn-1] - 1;
     title->block_start = d->pgc->cell_playback[title->cell_start].first_sector;
@@ -184,14 +212,6 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
             title->cell_end, title->block_start, title->block_end,
             title->block_count );
 
-    if( title->block_count < 2048  )
-    {
-        hb_log( "scan: title too short (%d blocks), ignoring",
-                title->block_count );
-        goto fail;
-    }
-
-
     /* Get duration */
     title->duration = 90LL * dvdtime2msec( &d->pgc->playback_time );
     title->hours    = title->duration / 90000 / 3600;
@@ -201,8 +221,10 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
             title->hours, title->minutes, title->seconds,
             title->duration / 90 );
 
-    /* Discard titles under 10 seconds */
-    if( !( title->hours | title->minutes ) && title->seconds < 10 )
+    /* 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;
@@ -238,23 +260,28 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
         {
             case 0x00:
                 audio->id    = ( ( 0x80 + position ) << 8 ) | 0xbd;
-                audio->codec = HB_ACODEC_AC3;
+                audio->config.in.codec = HB_ACODEC_AC3;
                 break;
 
             case 0x02:
             case 0x03:
                 audio->id    = 0xc0 + position;
-                audio->codec = HB_ACODEC_MPGA;
+                audio->config.in.codec = HB_ACODEC_MPGA;
                 break;
 
             case 0x04:
                 audio->id    = ( ( 0xa0 + position ) << 8 ) | 0xbd;
-                audio->codec = HB_ACODEC_LPCM;
+                audio->config.in.codec = HB_ACODEC_LPCM;
+                break;
+
+            case 0x06:
+                audio->id    = ( ( 0x88 + position ) << 8 ) | 0xbd;
+                audio->config.in.codec = HB_ACODEC_DCA;
                 break;
 
             default:
                 audio->id    = 0;
-                audio->codec = 0;
+                audio->config.in.codec = 0;
                 hb_log( "scan: unknown audio codec (%x)",
                         audio_format );
                 break;
@@ -284,18 +311,20 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
 
         lang = lang_for_code( vts->vtsi_mat->vts_audio_attr[i].lang_code );
 
-        snprintf( audio->lang, sizeof( audio->lang ), "%s (%s)",
+        snprintf( audio->config.lang.description, sizeof( audio->config.lang.description ), "%s (%s)",
             strlen(lang->native_name) ? lang->native_name : lang->eng_name,
-            audio->codec == HB_ACODEC_AC3 ? "AC3" : ( audio->codec ==
-                HB_ACODEC_MPGA ? "MPEG" : "LPCM" ) );
-        snprintf( audio->lang_simple, sizeof( audio->lang_simple ), "%s",
+            audio->config.in.codec == HB_ACODEC_AC3 ? "AC3" : ( audio->config.in.codec ==
+                HB_ACODEC_DCA ? "DTS" : ( audio->config.in.codec ==
+                HB_ACODEC_MPGA ? "MPEG" : "LPCM" ) ) );
+        snprintf( audio->config.lang.simple, sizeof( audio->config.lang.simple ), "%s",
                   strlen(lang->native_name) ? lang->native_name : lang->eng_name );
-        snprintf( audio->iso639_2, sizeof( audio->iso639_2 ), "%s",
+        snprintf( audio->config.lang.iso639_2, sizeof( audio->config.lang.iso639_2 ), "%s",
                   lang->iso639_2);
 
         hb_log( "scan: id=%x, lang=%s, 3cc=%s", audio->id,
-                audio->lang, audio->iso639_2 );
+                audio->config.lang.description, audio->config.lang.iso639_2 );
 
+        audio->config.in.track = i;
         hb_list_add( title->list_audio, audio );
     }
 
@@ -372,7 +401,8 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
         pgc_t * pgc_next;
 
         chapter = calloc( sizeof( hb_chapter_t ), 1 );
-        chapter->index = c;
+        /* remember the on-disc chapter number */
+        chapter->index = i + 1;
 
         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;
@@ -424,26 +454,8 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t )
             FindNextCell( d );
             d->cell_cur = d->cell_next;
         }
-
-        if( chapter->block_count < 2048 && chapter->index > 1 )
-        {
-            hb_log( "scan: chapter %d too short (%d blocks, "
-                    "cells=%d->%d), merging", chapter->index,
-                    chapter->block_count, chapter->cell_start,
-                    chapter->cell_end );
-            chapter_old = hb_list_item( title->list_chapter,
-                                        chapter->index - 2 );
-            chapter_old->cell_end    = chapter->cell_end;
-            chapter_old->block_end   = chapter->block_end;
-            chapter_old->block_count += chapter->block_count;
-            free( chapter );
-            chapter = chapter_old;
-        }
-        else
-        {
-            hb_list_add( title->list_chapter, chapter );
-            c++;
-        }
+        hb_list_add( title->list_chapter, chapter );
+        c++;
     }
 
     /* The durations we get for chapters aren't precise. Scale them so
@@ -517,13 +529,13 @@ int hb_dvd_start( hb_dvd_t * d, int title, int chapter )
     d->ttn = d->vmg->tt_srpt->title[title-1].vts_ttn;
     if( !( d->ifo = ifoOpen( d->reader, d->vts ) ) )
     {
-        hb_log( "dvd: ifoOpen failed for VTS %d", d->vts );
+        hb_error( "dvd: ifoOpen failed for VTS %d", d->vts );
         return 0;
     }
     if( !( d->file = DVDOpenFile( d->reader, d->vts,
                                   DVD_READ_TITLE_VOBS ) ) )
     {
-        hb_log( "dvd: DVDOpenFile failed for VTS %d", d->vts );
+        hb_error( "dvd: DVDOpenFile failed for VTS %d", d->vts );
         return 0;
     }
 
@@ -557,7 +569,9 @@ int hb_dvd_start( hb_dvd_t * d, int title, int chapter )
     d->next_vobu = d->block;
     d->pack_len  = 0;
     d->cell_overlap = 0;
-    
+    d->in_cell = 0;
+    d->in_sync = 2;
+
     return 1;
 }
 
@@ -600,6 +614,7 @@ int hb_dvd_seek( hb_dvd_t * d, float f )
         if( count < sizeCell )
         {
             d->cell_cur = i;
+            d->cur_cell_id = 0;
             FindNextCell( d );
 
             /* Now let hb_dvd_read find the next VOBU */
@@ -616,18 +631,56 @@ int hb_dvd_seek( hb_dvd_t * d, float f )
         return 0;
     }
 
+    /*
+     * Assume that we are in sync, even if we are not given that it is obvious
+     * that we are out of sync if we have just done a seek.
+     */
+    d->in_sync = 2;
+
     return 1;
 }
 
 
 /***********************************************************************
  * is_nav_pack
- ***********************************************************************
- * Pretty much directly lifted from libdvdread's play_title function.
- **********************************************************************/
+ ***********************************************************************/
 int is_nav_pack( unsigned char *buf )
 {
-    return ( buf[41] == 0xbf && buf[1027] == 0xbf );
+    /*
+     * The NAV Pack is comprised of the PCI Packet and DSI Packet, both
+     * of these start at known offsets and start with a special identifier.
+     *
+     * NAV = {
+     *  PCI = { 00 00 01 bf  # private stream header
+     *          ?? ??        # length
+     *          00           # substream
+     *          ...
+     *        }
+     *  DSI = { 00 00 01 bf  # private stream header
+     *          ?? ??        # length
+     *          01           # substream
+     *          ...
+     *        }
+     *
+     * The PCI starts at offset 0x26 into the sector, and the DSI starts at 0x400
+     *
+     * This information from: http://dvd.sourceforge.net/dvdinfo/
+     */
+    if( ( buf[0x26] == 0x00 &&      // PCI
+          buf[0x27] == 0x00 &&
+          buf[0x28] == 0x01 &&
+          buf[0x29] == 0xbf &&
+          buf[0x2c] == 0x00 ) &&
+        ( buf[0x400] == 0x00 &&     // DSI
+          buf[0x401] == 0x00 &&
+          buf[0x402] == 0x01 &&
+          buf[0x403] == 0xbf &&
+          buf[0x406] == 0x01 ) )
+    {
+        return ( 1 );
+    } else {
+        return ( 0 );
+    }
 }
 
 
@@ -638,34 +691,125 @@ int is_nav_pack( unsigned char *buf )
  **********************************************************************/
 int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b )
 {
+ top:
     if( !d->pack_len )
     {
         /* New pack */
         dsi_t dsi_pack;
-        int   error;
+        int   error = 0;
+
+        // if we've just finished the last cell of the title we don't
+        // want to read another block because our next_vobu pointer
+        // is probably invalid. Just return 'no data' & our caller
+        // should check and discover we're at eof.
+        if ( d->cell_cur > d->cell_end )
+            return 0;
 
-        error = 0;
-        
         for( ;; )
         {
-            int block, pack_len, next_vobu;
+            int block, pack_len, next_vobu, read_retry;
 
-            if( DVDReadBlocks( d->file, d->next_vobu, 1, b->data ) != 1 )
+            for( read_retry = 0; read_retry < 3; read_retry++ )
             {
-                hb_log( "dvd: DVDReadBlocks failed (%d)", d->next_vobu );
-                return 0;
+                if( DVDReadBlocks( d->file, d->next_vobu, 1, b->data ) == 1 )
+                {
+                    /*
+                     * Successful read.
+                     */
+                    break;
+                } else {
+                    hb_log( "dvd: Read Error on blk %d, attempt %d",
+                            d->next_vobu, read_retry );
+                }
+            }
+
+            if( read_retry == 3 )
+            {
+                hb_log( "dvd: vobu read error blk %d - skipping to cell %d",
+                        d->next_vobu, d->cell_next );
+                d->cell_cur  = d->cell_next;
+                if ( d->cell_cur > d->cell_end )
+                    return 0;
+                d->in_cell = 0;
+                d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector;
+                FindNextCell( d );
+                d->cell_overlap = 1;
+                continue;
             }
 
-            if ( !is_nav_pack( b->data ) ) { 
+            if ( !is_nav_pack( b->data ) ) {
                 (d->next_vobu)++;
+                if( d->in_sync == 1 ) {
+                    hb_log("dvd: Lost sync, searching for NAV pack at blk %d",
+                           d->next_vobu);
+                    d->in_sync = 0;
+                }
                 continue;
             }
 
             navRead_DSI( &dsi_pack, &b->data[DSI_START_BYTE] );
-            
+
+            if ( d->in_sync == 0 && d->cur_cell_id &&
+                 (d->cur_vob_id != dsi_pack.dsi_gi.vobu_vob_idn ||
+                  d->cur_cell_id != dsi_pack.dsi_gi.vobu_c_idn ) )
+            {
+                // We walked out of the cell we're supposed to be in.
+                // If we're not at the start of our next cell go there.
+                hb_log("dvd: left cell %d (%u,%u) for (%u,%u) at block %u",
+                       d->cell_cur, d->cur_vob_id, d->cur_cell_id,
+                       dsi_pack.dsi_gi.vobu_vob_idn, dsi_pack.dsi_gi.vobu_c_idn,
+                       d->next_vobu );
+                if ( d->next_vobu != d->pgc->cell_playback[d->cell_next].first_sector )
+                {
+                    d->next_vobu = d->pgc->cell_playback[d->cell_next].first_sector;
+                    d->cur_cell_id = 0;
+                    continue;
+                }
+            }
+
             block     = dsi_pack.dsi_gi.nv_pck_lbn;
             pack_len  = dsi_pack.dsi_gi.vobu_ea;
-            next_vobu = block + ( dsi_pack.vobu_sri.next_vobu & 0x7fffffff );
+
+            // 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 );
 
             if( pack_len >  0    &&
                 pack_len <  1024 &&
@@ -673,16 +817,6 @@ int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b )
                 ( block <= d->title_start + d->title_block_count ||
                   block <= d->title_end ) )
             {
-                /* XXX
-                   This looks like a valid VOBU, but actually we are
-                   just hoping */
-                if( error )
-                {
-#if 0
-                    hb_log( "dvd: found VOBU at %d (b %d, l %d, n %d)",
-                            d->next_vobu, block, pack_len, next_vobu );
-#endif
-                }
                 d->block     = block;
                 d->pack_len  = pack_len;
                 d->next_vobu = next_vobu;
@@ -690,13 +824,6 @@ int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b )
             }
 
             /* Wasn't a valid VOBU, try next block */
-            if( !error )
-            {
-#if 0
-                hb_log( "dvd: looking for a VOBU (%d)", d->next_vobu );
-#endif
-            }
-
             if( ++error > 1024 )
             {
                 hb_log( "dvd: couldn't find a VOBU after 1024 blocks" );
@@ -706,32 +833,99 @@ int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b )
             (d->next_vobu)++;
         }
 
-        if( dsi_pack.vobu_sri.next_vobu == SRI_END_OF_CELL )
+        if( d->in_sync == 0 || d->in_sync == 2 )
         {
-            d->cell_cur  = d->cell_next;
-            d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector;
-            FindNextCell( d );
-            d->cell_overlap = 1;
-            printf("DVD: End of Cell\n");
+            if( d->in_sync == 0 )
+            {
+                hb_log( "dvd: In sync with DVD at block %d", d->block );
+            }
+            d->in_sync = 1;
         }
-        
+
         // Revert the cell overlap, and check for a chapter break
-        if( dsi_pack.vobu_sri.prev_vobu == SRI_END_OF_CELL )
+        // If this cell is zero length (prev_vobu & next_vobu both
+        // set to END_OF_CELL) we need to check for beginning of
+        // cell before checking for end or we'll advance to the next
+        // cell too early and fail to generate a chapter mark when this
+        // cell starts a chapter.
+        if( ( dsi_pack.vobu_sri.prev_vobu & (1 << 31 ) ) == 0 ||
+            ( dsi_pack.vobu_sri.prev_vobu & 0x3fffffff ) == 0x3fffffff )
+        {
+            // A vobu that's not at the start of a cell can have an
+            // EOC prev pointer (this seems to be associated with some
+            // sort of drm). The rest of the content in the cell may be
+            // booby-trapped so treat this like an end-of-cell rather
+            // than a beginning of cell.
+            if ( d->pgc->cell_playback[d->cell_cur].first_sector < dsi_pack.dsi_gi.nv_pck_lbn &&
+                 d->pgc->cell_playback[d->cell_cur].last_sector >= dsi_pack.dsi_gi.nv_pck_lbn )
+            {
+                hb_log( "dvd: null prev_vobu in cell %d at block %d", d->cell_cur,
+                        d->block );
+                // treat like end-of-cell then go directly to start of next cell.
+                d->cell_cur  = d->cell_next;
+                d->in_cell = 0;
+                d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector;
+                FindNextCell( d );
+                d->cell_overlap = 1;
+                goto top;
+            }
+            else
+            {
+                if ( d->block != d->pgc->cell_playback[d->cell_cur].first_sector )
+                {
+                    hb_log( "dvd: beginning of cell %d at block %d", d->cell_cur,
+                           d->block );
+                }
+                if( d->in_cell )
+                {
+                    hb_error( "dvd: assuming missed end of cell %d", d->cell_cur );
+                    d->cell_cur  = d->cell_next;
+                    d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector;
+                    FindNextCell( d );
+                    d->cell_overlap = 1;
+                    d->in_cell = 0;
+                } else {
+                    d->in_cell = 1;
+                }
+                d->cur_vob_id = dsi_pack.dsi_gi.vobu_vob_idn;
+                d->cur_cell_id = dsi_pack.dsi_gi.vobu_c_idn;
+
+                if( d->cell_overlap )
+                {
+                    b->new_chap = hb_dvd_is_break( d );
+                    d->cell_overlap = 0;
+                }
+            }
+        }
+
+        if( ( dsi_pack.vobu_sri.next_vobu & (1 << 31 ) ) == 0 ||
+            ( dsi_pack.vobu_sri.next_vobu & 0x3fffffff ) == 0x3fffffff )
         {
-            printf("DVD: Beginning of Cell\n");
-            if( d->cell_overlap )
+            if ( d->block <= d->pgc->cell_playback[d->cell_cur].first_sector ||
+                 d->block > d->pgc->cell_playback[d->cell_cur].last_sector )
             {
-                b->new_chap = hb_dvd_is_break( d );
-                d->cell_overlap = 0;
+                hb_log( "dvd: end of cell %d at block %d", d->cell_cur,
+                        d->block );
             }
+            d->cell_cur  = d->cell_next;
+            d->in_cell = 0;
+            d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector;
+            FindNextCell( d );
+            d->cell_overlap = 1;
+
         }
     }
     else
     {
         if( DVDReadBlocks( d->file, d->block, 1, b->data ) != 1 )
         {
-            hb_log( "reader: DVDReadBlocks failed (%d)", d->block );
-            return 0;
+            // this may be a real DVD error or may be DRM. Either way
+            // we don't want to quit because of one bad block so set
+            // things up so we'll advance to the next vobu and recurse.
+            hb_error( "dvd: DVDReadBlocks failed (%d), skipping to vobu %u",
+                      d->block, d->next_vobu );
+            d->pack_len = 0;
+            goto top;  /* XXX need to restructure this routine & avoid goto */
         }
         d->pack_len--;
     }
@@ -751,7 +945,7 @@ int hb_dvd_chapter( hb_dvd_t * d )
 {
     int     i;
     int     pgc_id, pgn;
-       int     nr_of_ptts = d->ifo->vts_ptt_srpt->title[d->ttn-1].nr_of_ptts;
+    int     nr_of_ptts = d->ifo->vts_ptt_srpt->title[d->ttn-1].nr_of_ptts;
     pgc_t * pgc;
 
     for( i = nr_of_ptts - 1;
@@ -778,16 +972,16 @@ int hb_dvd_chapter( hb_dvd_t * d )
 /***********************************************************************
  * hb_dvd_is_break
  ***********************************************************************
- * Returns 1 if the current block is a new chapter start
+ * Returns chapter number if the current block is a new chapter start
  **********************************************************************/
 int hb_dvd_is_break( hb_dvd_t * d )
 {
-    int     i, j;
+    int     i;
     int     pgc_id, pgn;
        int     nr_of_ptts = d->ifo->vts_ptt_srpt->title[d->ttn-1].nr_of_ptts;
     pgc_t * pgc;
-    int     cell, chapter_length, cell_end;
-    
+    int     cell;
+
     for( i = nr_of_ptts - 1;
          i > 0;
          i-- )
@@ -804,38 +998,10 @@ int hb_dvd_is_break( hb_dvd_t * d )
         // This must not match against the start cell.
         if( pgc->cell_playback[cell].first_sector == d->block && cell != d->cell_start )
         {
-            /* Check to see if we merged this chapter into the previous one... */
-            /* As a note, merging chapters is probably bad practice for this very reason */
-            chapter_length = 0;
-            
-            if( i == nr_of_ptts - 1 )
-            {
-                cell_end = d->pgc->nr_of_cells;
-            }
-            else
-            {
-                cell_end = pgc->program_map[pgn] - 1;
-            }
-            
-            for( j = cell; j < cell_end; j++ )
-            {
-                chapter_length += pgc->cell_playback[j].last_sector + 1 - 
-                                  pgc->cell_playback[j].first_sector;
-            }
-            
-            if( chapter_length >= 2048 )
-            {
-                printf("DVD: Chapter Break Cell Found\n");
-                /* We have a chapter break */
-                return 1;
-            }
-            else
-            {
-                printf("DVD: Cell Found (%d)\n", chapter_length);
-            }
+            return i + 1;
         }
     }
-    
+
     return 0;
 }
 
@@ -881,6 +1047,9 @@ static void FindNextCell( hb_dvd_t * d )
              i++;
         }
         d->cell_next = d->cell_cur + i + 1;
+        hb_log( "dvd: Skipping multi-angle cells %d-%d",
+                d->cell_cur,
+                d->cell_next - 1 );
     }
     else
     {