Index: libhb/dvd.c =================================================================== --- libhb/dvd.c (revision 1372) +++ libhb/dvd.c (working copy) @@ -962,7 +962,7 @@ /*********************************************************************** * 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 ) { @@ -988,8 +988,7 @@ // This must not match against the start cell. if( pgc->cell_playback[cell].first_sector == d->block && cell != d->cell_start ) { - hb_log("dvd: Chapter Break Cell Found"); - return 1; + return i + 1; } } Index: libhb/decmpeg2.c =================================================================== --- libhb/decmpeg2.c (revision 1372) +++ libhb/decmpeg2.c (working copy) @@ -37,12 +37,15 @@ { mpeg2dec_t * libmpeg2; const mpeg2_info_t * info; + hb_job_t * job; int width; int height; int rate; int aspect_ratio; - int got_iframe; - int look_for_break; + int got_iframe; /* set when we get our first iframe */ + int look_for_iframe; /* need an iframe to add chap break */ + int look_for_break; /* need gop start to add chap break */ + uint32_t nframes; /* number of frames we've decoded */ int64_t last_pts; }; @@ -58,7 +61,6 @@ m->libmpeg2 = mpeg2_init(); m->info = mpeg2_info( m->libmpeg2 ); m->last_pts = -1; - m->look_for_break = 0; return m; } @@ -74,7 +76,6 @@ mpeg2_state_t state; hb_buffer_t * buf; uint8_t * data; - int chap_break = 0; /* Feed libmpeg2 */ if( buf_es->start > -1 ) @@ -117,10 +118,12 @@ } } } - else if( state == STATE_GOP && m->look_for_break == 2) + else if( state == STATE_GOP && m->look_for_break) { - hb_log("MPEG2: Group of pictures found, searching for I-Frame"); - m->look_for_break = 1; + // we were looking for a gop to add a chapter break - we found it + // so now start looking for an iframe. + m->look_for_iframe = m->look_for_break; + m->look_for_break = 0; } else if( ( state == STATE_SLICE || state == STATE_END ) && m->info->display_fbuf ) @@ -128,15 +131,8 @@ if( ( m->info->display_picture->flags & PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I ) { + // we got an iframe so we can start decoding video now m->got_iframe = 1; - - // If we are looking for a break, insert the chapter break on an I-Frame - if( m->look_for_break == 1 ) - { - hb_log("MPEG2: I-Frame Found"); - m->look_for_break = 0; - chap_break = 1; - } } if( m->got_iframe ) @@ -146,14 +142,6 @@ buf->sequence = buf_es->sequence; - // Was a good break point found? - if( chap_break ) - { - hb_log("MPEG2: Chapter Break Inserted"); - chap_break = 0; - buf->new_chap = 1; - } - memcpy( data, m->info->display_fbuf->buf[0], m->width * m->height ); data += m->width * m->height; @@ -187,6 +175,27 @@ } m->last_pts = buf->start; + if( m->look_for_iframe && ( m->info->display_picture->flags & + PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I ) + { + // we were waiting for an iframe to insert a chapter mark + // and we have one. + buf->new_chap = m->look_for_iframe; + m->look_for_iframe = 0; + const char *chap_name = ""; + if ( m->job && buf->new_chap > 0 && + hb_list_item( m->job->title->list_chapter, + buf->new_chap - 1 ) ) + { + hb_chapter_t * c = hb_list_item( m->job->title->list_chapter, + buf->new_chap - 1 ); + chap_name = c->title; + } + hb_log( "mpeg2: chapter %d \"%s\" at frame %u time %lld", + buf->new_chap, chap_name, m->nframes, buf->start ); + } + ++m->nframes; + flag = m->info->display_picture->flags; /* Uncomment this block to see frame-by-frame picture flags, as the video encodes. @@ -362,6 +371,8 @@ pv->libmpeg2 = hb_libmpeg2_init(); pv->list = hb_list_init(); + pv->libmpeg2->job = job; + return 0; } @@ -380,8 +391,7 @@ // stream. We need to shift it. if( (*buf_in)->new_chap ) { - hb_log("MPEG2: Chapter Break Cell Found, searching for GOP"); - pv->libmpeg2->look_for_break = 2; + pv->libmpeg2->look_for_break = (*buf_in)->new_chap; (*buf_in)->new_chap = 0; } Index: libhb/encx264.c =================================================================== --- libhb/encx264.c (revision 1372) +++ libhb/encx264.c (working copy) @@ -50,6 +50,7 @@ x264_picture_t pic_in; uint8_t *x264_allocated_pic; + int chap_mark; // saved chap mark when we're propagating it int64_t dts_next; // DTS start time value for next output frame int64_t last_stop; // Debugging - stop time of previous input frame int64_t init_delay; @@ -384,6 +385,7 @@ if( pv->next_chap == 0 ) { pv->next_chap = in->start; + pv->chap_mark = in->new_chap; } /* don't let 'work_loop' put a chapter mark on the wrong buffer */ in->new_chap = 0; @@ -496,7 +498,7 @@ if( pv->next_chap != 0 && pv->next_chap <= pic_out.i_pts ) { pv->next_chap = 0; - buf->new_chap = 1; + buf->new_chap = pv->chap_mark; } break; case X264_TYPE_I: Index: libhb/muxmp4.c =================================================================== --- libhb/muxmp4.c (revision 1372) +++ libhb/muxmp4.c (working copy) @@ -100,10 +100,16 @@ ********************************************************************** * Creates a buffer for a text track sample *********************************************************************/ -static struct hb_text_sample_s *MP4GenerateChapterSample( hb_mux_object_t * m, uint64_t duration ) +static struct hb_text_sample_s *MP4GenerateChapterSample( hb_mux_object_t * m, + uint64_t duration, + int chapter ) { - int chapter = m->current_chapter; - hb_chapter_t *chapter_data = hb_list_item( m->job->title->list_chapter, chapter - 1 ); + // We substract 1 from the chapter number because the chapters start at + // 1 but our name array starts at 0. We substract another 1 because we're + // writing the text of the previous chapter mark (when we get the start + // of chapter 2 we know the duration of chapter 1 & can write its mark). + hb_chapter_t *chapter_data = hb_list_item( m->job->title->list_chapter, + chapter - 2 ); char tmp_buffer[1024]; char *string = tmp_buffer; @@ -116,7 +122,7 @@ if( strlen(string) == 0 || strlen(string) >= 1024 ) { - snprintf( tmp_buffer, 1023, "Chapter %03i", chapter ); + snprintf( tmp_buffer, 1023, "Chapter %03i", chapter - 2 ); string = tmp_buffer; } @@ -383,7 +389,7 @@ duration += buf->renderOffset * m->samplerate / 90000; } - sample = MP4GenerateChapterSample( m, duration ); + sample = MP4GenerateChapterSample( m, duration, buf->new_chap ); if( !MP4WriteSample(m->file, m->chapter_track, @@ -396,7 +402,7 @@ *job->die = 1; } free(sample); - m->current_chapter++; + m->current_chapter = buf->new_chap; m->chapter_duration += duration; } @@ -461,7 +467,9 @@ /* Write our final chapter marker */ if( m->job->chapter_markers ) { - struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, (m->sum_dur - m->chapter_duration) ); + struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, + (m->sum_dur - m->chapter_duration), + m->current_chapter + 1 ); if( !MP4WriteSample(m->file, m->chapter_track, Index: libhb/sync.c =================================================================== --- libhb/sync.c (revision 1372) +++ libhb/sync.c (working copy) @@ -52,6 +52,7 @@ int video_sequence; int count_frames; int count_frames_max; + int chap_mark; /* to propagate chapter mark across a drop */ hb_buffer_t * cur; /* The next picture to process */ /* Audio */ @@ -344,6 +345,11 @@ } ++pv->drop_count; buf_tmp = hb_fifo_get( job->fifo_raw ); + if ( buf_tmp->new_chap ) + { + // don't drop a chapter mark when we drop the buffer + pv->chap_mark = buf_tmp->new_chap; + } hb_buffer_close( &buf_tmp ); continue; } @@ -521,6 +527,13 @@ buf_tmp->start = pv->next_start; pv->next_start += duration; buf_tmp->stop = pv->next_start; + if ( pv->chap_mark ) + { + // we have a pending chapter mark from a recent drop - put it on this + // buffer (this may make it one frame late but we can't do any better). + buf_tmp->new_chap = pv->chap_mark; + pv->chap_mark = 0; + } /* If we have a subtitle for this picture, copy it */ /* FIXME: we should avoid this memcpy */ Index: libhb/work.c =================================================================== --- libhb/work.c (revision 1372) +++ libhb/work.c (working copy) @@ -840,8 +840,9 @@ // 'buf_in' to NULL so that this code won't generate spurious duplicates.) if( buf_in && buf_out && buf_in->new_chap && buf_in->start == buf_out->start) { - hb_log("work %s: Copying Chapter Break @ %lld", w->name, buf_in->start); - buf_out->new_chap = 1; + // restore log below to debug chapter mark propagation problems + //hb_log("work %s: Copying Chapter Break @ %lld", w->name, buf_in->start); + buf_out->new_chap = buf_in->new_chap; } if( buf_in ) Index: libhb/muxmkv.c =================================================================== --- libhb/muxmkv.c (revision 1372) +++ libhb/muxmkv.c (working copy) @@ -265,7 +265,12 @@ /* Make sure we're not writing a chapter that has 0 length */ if (mux_data->prev_chapter_tc != timecode) { - chapter_data = hb_list_item( title->list_chapter, mux_data->current_chapter++ ); + if ( buf->new_chap ) + { + mux_data->current_chapter = buf->new_chap - 2; + } + chapter_data = hb_list_item( title->list_chapter, + mux_data->current_chapter++ ); tmp_buffer[0] = '\0'; if( chapter_data != NULL )