diff options
author | dynaflash <[email protected]> | 2007-04-25 17:24:58 +0000 |
---|---|---|
committer | dynaflash <[email protected]> | 2007-04-25 17:24:58 +0000 |
commit | cdcdac58032b929a7edea0459047a9cb56da767d (patch) | |
tree | c0aad497331fe94fb7f6b13b9600283f9350cf59 /libhb | |
parent | e1f55561971a286170d003d20eff51c9a5563f43 (diff) |
Fix Previous Bad commit for Cyanders Chapter Markers
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@548 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/decmpeg2.c | 33 | ||||
-rw-r--r-- | libhb/demuxmpeg.c | 6 | ||||
-rw-r--r-- | libhb/dvd.c | 92 | ||||
-rw-r--r-- | libhb/encxvid.c | 1 | ||||
-rw-r--r-- | libhb/fifo.c | 2 | ||||
-rw-r--r-- | libhb/internal.h | 2 | ||||
-rw-r--r-- | libhb/muxmp4.c | 147 | ||||
-rw-r--r-- | libhb/sync.c | 10 | ||||
-rw-r--r-- | libhb/work.c | 8 |
9 files changed, 263 insertions, 38 deletions
diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c index 214444a05..4fb6ad76b 100644 --- a/libhb/decmpeg2.c +++ b/libhb/decmpeg2.c @@ -21,6 +21,7 @@ struct hb_libmpeg2_s int height; int rate; int got_iframe; + int look_for_break; int64_t last_pts; }; @@ -36,6 +37,7 @@ hb_libmpeg2_t * hb_libmpeg2_init() m->libmpeg2 = mpeg2_init(); m->info = mpeg2_info( m->libmpeg2 ); m->last_pts = -1; + m->look_for_break = 0; return m; } @@ -51,6 +53,7 @@ int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, mpeg2_state_t state; hb_buffer_t * buf; uint8_t * data; + int chap_break = 0; /* Feed libmpeg2 */ if( buf_es->start > -1 ) @@ -86,6 +89,11 @@ int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, } } } + else if( state == STATE_GOP && m->look_for_break == 2) + { + printf("MPEG2: Group of pictures found, searching for I-Frame\n"); + m->look_for_break = 1; + } else if( ( state == STATE_SLICE || state == STATE_END ) && m->info->display_fbuf ) { @@ -93,6 +101,14 @@ int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I ) { 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 ) + { + printf("MPEG2: I-Frame Found\n"); + m->look_for_break = 0; + chap_break = 1; + } } if( m->got_iframe ) @@ -100,6 +116,14 @@ int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, buf = hb_buffer_init( m->width * m->height * 3 / 2 ); data = buf->data; + // Was a good break point found? + if( chap_break ) + { + printf("MPEG2: Chapter Break Inserted\n"); + chap_break = 0; + buf->new_chap = 1; + } + memcpy( data, m->info->display_fbuf->buf[0], m->width * m->height ); data += m->width * m->height; @@ -208,6 +232,15 @@ int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_work_private_t * pv = w->private_data; hb_buffer_t * buf, * last = NULL; + // The reader found a chapter break, consume it completely, and remove it from the + // stream. We need to shift it. + if( (*buf_in)->new_chap ) + { + printf("MPEG2: Chapter Break Cell Found, searching for GOP\n"); + pv->libmpeg2->look_for_break = 2; + (*buf_in)->new_chap = 0; + } + hb_libmpeg2_decode( pv->libmpeg2, *buf_in, pv->list ); *buf_out = NULL; diff --git a/libhb/demuxmpeg.c b/libhb/demuxmpeg.c index 721478e80..5aefc3743 100644 --- a/libhb/demuxmpeg.c +++ b/libhb/demuxmpeg.c @@ -110,8 +110,10 @@ int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es ) /* Here we hit we ES payload */ buf_es = hb_buffer_init( pes_packet_end - pos ); - buf_es->id = id; - buf_es->start = pts; + buf_es->id = id; + buf_es->start = pts; + buf_es->new_chap = buf_ps->new_chap; // Consume a chapter break, and apply it to the ES. + buf_ps->new_chap = 0; memcpy( buf_es->data, d + pos, pes_packet_end - pos ); hb_list_add( list_es, buf_es ); diff --git a/libhb/dvd.c b/libhb/dvd.c index 9b4ba3fe7..b26c55995 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -30,6 +30,7 @@ struct hb_dvd_s int title_block_count; int cell_cur; int cell_next; + int cell_overlap; int block; int pack_len; int next_vobu; @@ -555,7 +556,8 @@ int hb_dvd_start( hb_dvd_t * d, int title, int chapter ) d->block = d->pgc->cell_playback[d->cell_cur].first_sector; d->next_vobu = d->block; d->pack_len = 0; - + d->cell_overlap = 0; + return 1; } @@ -709,6 +711,19 @@ int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b ) 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"); + } + + // Revert the cell overlap, and check for a chapter break + if( dsi_pack.vobu_sri.prev_vobu == SRI_END_OF_CELL ) + { + printf("DVD: Beginning of Cell\n"); + if( d->cell_overlap ) + { + b->new_chap = hb_dvd_is_break( d ); + d->cell_overlap = 0; + } } } else @@ -736,19 +751,20 @@ 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; pgc_t * pgc; - for( i = 0; - i < d->ifo->vts_ptt_srpt->title[d->ttn-1].nr_of_ptts; - i++ ) + for( i = nr_of_ptts - 1; + i >= 0; + i-- ) { /* Get pgc for chapter (i+1) */ pgc_id = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[i].pgcn; pgn = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[i].pgn; pgc = d->ifo->vts_pgcit->pgci_srp[pgc_id-1].pgc; - if( d->cell_cur >= pgc->program_map[pgn-1] - 1 && - d->cell_cur <= pgc->nr_of_cells - 1 ) + if( d->cell_cur - d->cell_overlap >= pgc->program_map[pgn-1] - 1 && + d->cell_cur - d->cell_overlap <= pgc->nr_of_cells - 1 ) { /* We are in this chapter */ return i + 1; @@ -760,6 +776,70 @@ int hb_dvd_chapter( hb_dvd_t * d ) } /*********************************************************************** + * hb_dvd_is_break + *********************************************************************** + * Returns 1 if the current block is a new chapter start + **********************************************************************/ +int hb_dvd_is_break( hb_dvd_t * d ) +{ + int i, j; + 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; + + for( i = nr_of_ptts - 1; + i > 0; + i-- ) + { + /* Get pgc for chapter (i+1) */ + pgc_id = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[i].pgcn; + pgn = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[i].pgn; + pgc = d->ifo->vts_pgcit->pgci_srp[pgc_id-1].pgc; + cell = pgc->program_map[pgn-1] - 1; + + if( cell <= d->cell_start ) + break; + + // 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 0; +} + +/*********************************************************************** * hb_dvd_close *********************************************************************** * Closes and frees everything diff --git a/libhb/encxvid.c b/libhb/encxvid.c index fbaa5a135..7430aca0f 100644 --- a/libhb/encxvid.c +++ b/libhb/encxvid.c @@ -160,6 +160,7 @@ int encxvidWork( hb_work_object_t * w, hb_buffer_t ** buf_in, buf = hb_buffer_init( 3 * job->width * job->height / 2 ); buf->start = in->start; buf->stop = in->stop; + //buf->chap = in->chap; memset( &frame, 0, sizeof( frame ) ); diff --git a/libhb/fifo.c b/libhb/fifo.c index 323406538..fe03c47f9 100644 --- a/libhb/fifo.c +++ b/libhb/fifo.c @@ -129,7 +129,7 @@ hb_buffer_t * hb_fifo_get( hb_fifo_t * f ) b->next = NULL; f->size -= 1; hb_unlock( f->lock ); - + return b; } diff --git a/libhb/internal.h b/libhb/internal.h index efe721e12..f950205d5 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -37,6 +37,7 @@ struct hb_buffer_s int id; int64_t start; int64_t stop; + int new_chap; int key; /* Holds the output PTS from x264, for use by b-frame offsets in muxmp4.c */ @@ -111,6 +112,7 @@ void hb_dvd_stop( hb_dvd_t * ); int hb_dvd_seek( hb_dvd_t *, float ); int hb_dvd_read( hb_dvd_t *, hb_buffer_t * ); int hb_dvd_chapter( hb_dvd_t * ); +int hb_dvd_is_break( hb_dvd_t * d ); void hb_dvd_close( hb_dvd_t ** ); /*********************************************************************** diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index 7aae352cd..e2de1ce86 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -27,6 +27,10 @@ struct hb_mux_object_s /* Cumulated durations so far, in timescale units (see MP4Mux) */ uint64_t sum_dur; + /* Chapter state information for muxing */ + MP4TrackId chapter_track; + int current_chapter; + uint64_t chapter_duration; }; struct hb_mux_data_s @@ -34,6 +38,91 @@ struct hb_mux_data_s MP4TrackId track; }; +struct hb_text_sample_s +{ + uint8_t sample[1280]; + uint32_t length; + MP4Duration duration; +}; + +/********************************************************************** + * MP4CreateTextSample + ********************************************************************** + * Creates a buffer for a text track sample + *********************************************************************/ +static struct hb_text_sample_s *MP4CreateTextSample( char *textString, uint64_t duration ) +{ + struct hb_text_sample_s *sample = NULL; + int stringLength = strlen(textString); + int x; + + if( stringLength < 1024 ) + { + sample = malloc( sizeof( struct hb_text_sample_s ) ); + + //textLength = (stringLength; // Account for BOM + sample->length = stringLength + 2 + 12; // Account for text length code and other marker + sample->duration = (MP4Duration)duration; + + // 2-byte length marker + sample->sample[0] = (stringLength >> 8) & 0xff; + sample->sample[1] = stringLength & 0xff; + + strncpy( (char *)&(sample->sample[2]), textString, stringLength ); + + x = 2 + stringLength; + + // Modifier Length Marker + sample->sample[x] = 0x00; + sample->sample[x+1] = 0x00; + sample->sample[x+2] = 0x00; + sample->sample[x+3] = 0x0C; + + // Modifier Type Code + sample->sample[x+4] = 'e'; + sample->sample[x+5] = 'n'; + sample->sample[x+6] = 'c'; + sample->sample[x+7] = 'd'; + + // Modifier Value + sample->sample[x+8] = 0x00; + sample->sample[x+9] = 0x00; + sample->sample[x+10] = (256 >> 8) & 0xff; + sample->sample[x+11] = 256 & 0xff; + } + + return sample; +} + +/********************************************************************** + * MP4GenerateChapterSample + ********************************************************************** + * Creates a buffer for a text track sample + *********************************************************************/ +static struct hb_text_sample_s *MP4GenerateChapterSample( hb_mux_object_t * m, uint64_t duration ) +{ + int chapter = m->current_chapter; + hb_chapter_t *chapter_data = hb_list_item( m->job->title->list_chapter, chapter - 1 ); + char tmp_buffer[1024]; + char *string = tmp_buffer; + + tmp_buffer[0] = '\0'; + + if( chapter_data != NULL ) + { + string = chapter_data->title; + } + + if( strlen(string) == 0 || strlen(string) >= 1024 ) + { + snprintf( tmp_buffer, 1023, "Chapter %03i", chapter ); + string = tmp_buffer; + } + + return MP4CreateTextSample( string, duration ); +} + + /********************************************************************** * MP4Init ********************************************************************** @@ -171,36 +260,15 @@ static int MP4Init( hb_mux_object_t * m ) } - if (job->chapter_markers) { - + if (job->chapter_markers) + { /* add a text track for the chapters */ MP4TrackId textTrack; - textTrack = MP4AddChapterTextTrack(m->file, firstAudioTrack); - - /* write the chapter markers for each selected chapter */ - char markerBuf[13]; - hb_chapter_t * chapter; - MP4Duration chapterDuration; - float fOrigDuration, fTimescale; - float fTSDuration; - - for( i = job->chapter_start - 1; i <= job->chapter_end - 1; i++ ) - { - chapter = hb_list_item( title->list_chapter, i ); - - fOrigDuration = chapter->duration; - fTimescale = job->arate; - fTSDuration = (fOrigDuration / 90000) * fTimescale; - chapterDuration = (MP4Duration)fTSDuration; - - sprintf(markerBuf, " Chapter %03i", i + 1); - markerBuf[0] = 0; - markerBuf[1] = 11; // "Chapter xxx" - MP4WriteSample(m->file, textTrack, (u_int8_t*)markerBuf, 13, chapterDuration, 0, true); - - } - + + m->chapter_track = textTrack; + m->chapter_duration = 0; + m->current_chapter = job->chapter_start; } return 0; @@ -214,7 +282,21 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, uint64_t duration; if( mux_data == job->mux_data ) - { + { + /* Add the sample before the new frame. + It is important that this be calculated prior to the duration + of the new video sample, as we want to sync to right after it. + (This is because of how durations for text tracks work in QT) */ + if( job->chapter_markers && buf->new_chap ) + { + struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, (m->sum_dur - m->chapter_duration) ); + + MP4WriteSample(m->file, m->chapter_track, sample->sample, sample->length, sample->duration, 0, true); + free(sample); + m->current_chapter++; + m->chapter_duration = m->sum_dur; + } + /* Video */ /* Because we use the audio samplerate as the timescale, we have to use potentially variable durations so the video @@ -253,6 +335,15 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, static int MP4End( hb_mux_object_t * m ) { + /* Write our final chapter marker */ + if( m->job->chapter_markers ) + { + struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, (m->sum_dur - m->chapter_duration) ); + + MP4WriteSample(m->file, m->chapter_track, sample->sample, sample->length, sample->duration, 0, true); + free(sample); + } + #if 0 hb_job_t * job = m->job; char filename[1024]; memset( filename, 0, 1024 ); diff --git a/libhb/sync.c b/libhb/sync.c index fb5d704ac..6ebbf6e0d 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -244,6 +244,7 @@ static int SyncVideo( hb_work_object_t * w ) hb_buffer_t * cur, * next, * sub = NULL; hb_job_t * job = pv->job; int64_t pts_expected; + int chap_break; if( pv->done ) { @@ -310,8 +311,11 @@ static int SyncVideo( hb_work_object_t * w ) } /* Trash current picture */ + /* Also, make sure we don't trash a chapter break */ + chap_break = cur->new_chap; hb_buffer_close( &cur ); pv->cur = cur = hb_fifo_get( job->fifo_raw ); + cur->new_chap |= chap_break; // Don't stomp existing chapter breaks /* Calculate new offset */ pv->pts_offset_old = pv->pts_offset; @@ -358,8 +362,12 @@ static int SyncVideo( hb_work_object_t * w ) { /* The current frame is too old but the next one matches, let's trash */ + /* Also, make sure we don't trash a chapter break */ + chap_break = cur->new_chap; hb_buffer_close( &cur ); pv->cur = cur = hb_fifo_get( job->fifo_raw ); + cur->new_chap |= chap_break; // Make sure we don't stomp the existing one. + continue; } @@ -377,7 +385,7 @@ static int SyncVideo( hb_work_object_t * w ) buf_tmp = cur; pv->cur = cur = hb_fifo_get( job->fifo_raw ); } - + /* Replace those MPEG-2 dates with our dates */ buf_tmp->start = (uint64_t) pv->count_frames * pv->job->vrate_base / 300; diff --git a/libhb/work.c b/libhb/work.c index a4dcb4514..3e5ec4a78 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -535,6 +535,14 @@ static void work_loop( void * _w ) // w->thread_sleep_interval = MAX(1, (w->thread_sleep_interval - 1)); w->work( w, &buf_in, &buf_out ); + + // Propogate any chapter breaks for the worker + if( buf_in && buf_out && buf_in->new_chap ) + { + printf("WORK: Copying Chapter Break\n"); + buf_out->new_chap = 1; + } + if( buf_in ) { hb_buffer_close( &buf_in ); |