summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authordynaflash <[email protected]>2007-04-25 17:24:58 +0000
committerdynaflash <[email protected]>2007-04-25 17:24:58 +0000
commitcdcdac58032b929a7edea0459047a9cb56da767d (patch)
treec0aad497331fe94fb7f6b13b9600283f9350cf59 /libhb
parente1f55561971a286170d003d20eff51c9a5563f43 (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.c33
-rw-r--r--libhb/demuxmpeg.c6
-rw-r--r--libhb/dvd.c92
-rw-r--r--libhb/encxvid.c1
-rw-r--r--libhb/fifo.c2
-rw-r--r--libhb/internal.h2
-rw-r--r--libhb/muxmp4.c147
-rw-r--r--libhb/sync.c10
-rw-r--r--libhb/work.c8
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 );