Index: test/test.c =================================================================== --- test/test.c (revision 1601) +++ test/test.c (working copy) @@ -318,11 +318,17 @@ for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) { chapter = hb_list_item( title->list_chapter, i ); - fprintf( stderr, " + %d: cells %d->%d, %d blocks, duration " - "%02d:%02d:%02d\n", chapter->index, - chapter->cell_start, chapter->cell_end, - chapter->block_count, chapter->hours, chapter->minutes, - chapter->seconds ); + if (chapter->use_frame) + fprintf( stderr, " + %d: frame=%lld, duration " + "%02d:%02d:%02d\n", chapter->index, + chapter->frame, chapter->hours, chapter->minutes, + chapter->seconds ); + else + fprintf( stderr, " + %d: cells %d->%d, %d blocks, duration " + "%02d:%02d:%02d\n", chapter->index, + chapter->cell_start, chapter->cell_end, + chapter->block_count, chapter->hours, chapter->minutes, + chapter->seconds ); } fprintf( stderr, " + audio tracks:\n" ); for( i = 0; i < hb_list_count( title->list_audio ); i++ ) @@ -452,18 +458,6 @@ /* Set job settings */ job = title->job; - PrintTitleInfo( title ); - - if( chapter_start && chapter_end ) - { - job->chapter_start = MAX( job->chapter_start, - chapter_start ); - job->chapter_end = MIN( job->chapter_end, - chapter_end ); - job->chapter_end = MAX( job->chapter_start, - job->chapter_end ); - } - if (preset) { fprintf( stderr, "+ Using preset: %s", preset_name); @@ -719,6 +713,12 @@ int row = 0; int chapter = 0; + /* extract chapter 1 as see if it was a stream, if + so we need to allocate a chapter for each row + of the marker file. */ + hb_chapter_t* chapter1 = hb_list_item( job->title->list_chapter, 0); + int alloc_chapters = (chapter1 && chapter1->use_frame); + fprintf( stderr, "Reading chapter markers from file %s\n", marker_file ); if( file == NULL ) @@ -740,8 +740,17 @@ /* We have a chapter name */ if( cell->cell_col == 1 && row == cell->cell_row ) { - /* If we have a valid chapter, copy the string an terminate it */ - if( chapter >= job->chapter_start && chapter <= job->chapter_end ) + /* if the chapter in the marker file doesn't yet exist, add one */ + if (alloc_chapters && !hb_list_item( job->title->list_chapter, chapter - 1)) { + hb_chapter_t * new_chapter_p; + new_chapter_p = calloc( sizeof( hb_chapter_t ), 1 ); + new_chapter_p->index = chapter; + hb_list_add( job->title->list_chapter, new_chapter_p ); + } + + /* If we have a valid chapter, copy the string an terminate it. + NOTE: if allocating chapters the chapter_start and chapter_end are not yet valid. */ + if( alloc_chapters || (chapter >= job->chapter_start && chapter <= job->chapter_end) ) { hb_chapter_t * chapter_s; @@ -751,11 +760,79 @@ } } + /* We have a chapter frame location -- + this value will be ignored if not for a + ffmpeg or transport stream */ + if( cell->cell_col == 2 && row == cell->cell_row ) + { + /* If we have a valid chapter, record the frame number. + NOTE: if allocating chapters the chapter_start and chapter_end are not yet valid. */ + if( alloc_chapters || (chapter >= job->chapter_start && chapter <= job->chapter_end) ) + { + hb_chapter_t * chapter_s; + chapter_s = hb_list_item( job->title->list_chapter, chapter - 1); + chapter_s->frame = atoi( cell->cell_text ); + chapter_s->use_frame = 1; + } + } + + hb_dispose_cell( cell ); } hb_close_csv_file( file ); + + if (alloc_chapters) { + /* if we were allocating chapters as we went, we have some cleanup to do */ + /* we need to fill in the duration information, the total title duration + is in chapter 1 from the title scan */ + + /* precalculate the amount of duration used by each from from the fps */ + uint64_t duration_per_frame = 90000LL * job->title->rate_base / job->title->rate; + + /* setup the loop with chapter 1 */ + hb_chapter_t* last_chapter_p = hb_list_item( job->title->list_chapter, 0); + uint64_t rem_duration = last_chapter_p->duration/*title duration*/; + int number_of_chapters = hb_list_count(job->title->list_chapter); + int chapter; + int seconds; + + for(chapter = 2; chapter <= number_of_chapters ; chapter++) + { + /* get next chapter */ + hb_chapter_t * chapter_p; + chapter_p = hb_list_item( job->title->list_chapter, chapter - 1); + + /* calculate duration used by previous chapter */ + last_chapter_p->duration = (chapter_p->frame - last_chapter_p->frame) * duration_per_frame; + + /* keep track of whats still left */ + rem_duration -= last_chapter_p->duration; + + /* make the pretty version of duration */ + seconds = ( last_chapter_p->duration + 45000 ) / 90000; + last_chapter_p->hours = seconds / 3600; + last_chapter_p->minutes = ( seconds % 3600 ) / 60; + last_chapter_p->seconds = seconds % 60; + + /* keep previous chapter around to fill in next */ + last_chapter_p = chapter_p; + } + + /* final chapter goes for rem_duration */ + last_chapter_p->duration = rem_duration; + seconds = ( rem_duration + 45000 ) / 90000; + last_chapter_p->hours = seconds / 3600; + last_chapter_p->minutes = ( seconds % 3600 ) / 60; + last_chapter_p->seconds = seconds % 60; + + /* setup the chapter_start/end correctly + now that we know how many chapters + there are */ + job->chapter_start = 1; + job->chapter_end = number_of_chapters; + } } } else @@ -775,6 +852,18 @@ } } + PrintTitleInfo( title ); + + if( chapter_start && chapter_end ) + { + job->chapter_start = MAX( job->chapter_start, + chapter_start ); + job->chapter_end = MIN( job->chapter_end, + chapter_end ); + job->chapter_end = MAX( job->chapter_start, + job->chapter_end ); + } + if( crop[0] >= 0 && crop[1] >= 0 && crop[2] >= 0 && crop[3] >= 0 ) { Index: libhb/stream.c =================================================================== --- libhb/stream.c (revision 1601) +++ libhb/stream.c (working copy) @@ -101,6 +101,8 @@ int last_error_count; /* # errors at last error message */ int packetsize; /* Transport Stream packet size */ + int last_chapter; /* chapter number of last seen chapter */ + int64_t ts_lastpcr; /* the last pcr we found in the TS stream */ int64_t ts_nextpcr; /* the next pcr to put in a PS packet */ @@ -176,10 +178,11 @@ /*********************************************************************** * Local prototypes **********************************************************************/ +static int hb_stream_chapter_start( hb_stream_t *stream ); static void hb_stream_duration(hb_stream_t *stream, hb_title_t *inTitle); static void hb_ts_stream_init(hb_stream_t *stream); static void hb_ts_stream_find_pids(hb_stream_t *stream); -static int hb_ts_stream_decode(hb_stream_t *stream, uint8_t *obuf); +static int hb_ts_stream_decode(hb_stream_t *stream, hb_buffer_t *b); static void hb_ts_stream_reset(hb_stream_t *stream); static hb_audio_t *hb_ts_stream_set_audio_id_and_codec(hb_stream_t *stream, int aud_pid_index); @@ -612,6 +615,7 @@ // One Chapter hb_chapter_t * chapter; chapter = calloc( sizeof( hb_chapter_t ), 1 ); + chapter->use_frame = 1; chapter->index = 1; chapter->duration = aTitle->duration; chapter->hours = aTitle->hours; @@ -1021,7 +1025,7 @@ } return 1; } - return hb_ts_stream_decode( src_stream, b->data ); + return hb_ts_stream_decode( src_stream, b ); } /*********************************************************************** @@ -2045,8 +2049,9 @@ *********************************************************************** * **********************************************************************/ -static int hb_ts_stream_decode( hb_stream_t *stream, uint8_t *obuf ) +static int hb_ts_stream_decode( hb_stream_t *stream, hb_buffer_t *b ) { + uint8_t* obuf = b->data; /* * stash the output buffer pointer in our stream so we don't have to * pass it & its original value to everything we call. @@ -2186,6 +2191,7 @@ stream->ts_foundfirst[0] = 1; } ++stream->frames; + b->new_chap = hb_stream_chapter_start(stream); } else if ( ! stream->ts_foundfirst[curstream] ) { @@ -2500,6 +2506,7 @@ // One Chapter hb_chapter_t * chapter; chapter = calloc( sizeof( hb_chapter_t ), 1 ); + chapter->use_frame = 1; chapter->index = 1; chapter->duration = title->duration; chapter->hours = title->hours; @@ -2546,6 +2553,33 @@ return (int64_t)( (double)pts * conv_factor ); } +static int hb_stream_chapter_start( hb_stream_t *stream ) +{ + /* only look for chapter start if not scanning */ + if (stream->title) { + int chapter = stream->last_chapter + 1; + hb_chapter_t * chapter_p; + chapter_p = hb_list_item( stream->title->list_chapter, chapter - 1); + + /* just in case we somehow missed the frame for a chapter walk + forward until we are in the right place */ + while (chapter_p->frame < stream->frames) { + ++chapter; + ++stream->last_chapter; + chapter_p = hb_list_item( stream->title->list_chapter, chapter - 1); + } + + /* return this chapter if we just read the start frame */ + if (chapter_p->frame == stream->frames) { + hb_log("start of chapter %d read", chapter); + stream->last_chapter = chapter; + return chapter; + } + } + + return 0; +} + static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ) { AVPacket pkt; @@ -2568,6 +2602,10 @@ av_q2d(stream->ffmpeg_ic->streams[pkt.stream_index]->time_base)*90000. ); buf->renderOffset = av_to_hb_pts( pkt.pts, av_q2d(stream->ffmpeg_ic->streams[pkt.stream_index]->time_base)*90000. ); + + ++stream->frames; + buf->new_chap = hb_stream_chapter_start(stream); + av_free_packet( &pkt ); return 1; } Index: libhb/common.h =================================================================== --- libhb/common.h (revision 1601) +++ libhb/common.h (working copy) @@ -390,6 +390,12 @@ int block_end; int block_count; + /* 1 if chapter is a bogus chapter for the full title (see + stream.c), or frame location specified in marker file */ + int use_frame; + /* chapter location specified from marker file */ + uint64_t frame; + /* Visual-friendly duration */ int hours; int minutes;