diff options
author | eddyg <[email protected]> | 2007-10-08 23:33:32 +0000 |
---|---|---|
committer | eddyg <[email protected]> | 2007-10-08 23:33:32 +0000 |
commit | b3178968037a18c721a66e2669ae6f040a12196a (patch) | |
tree | 98e31e044e92fc6eff6aa7121778df45e7c53df6 /libhb | |
parent | 803933145cbdd7681e3dcaa0124764657ecaea4f (diff) |
Don't drop subtitles when crossing PTS discontinuities by using buffer sequence numbers to determine where in the stream the buffer came from.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1011 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/deca52.c | 11 | ||||
-rw-r--r-- | libhb/decmpeg2.c | 2 | ||||
-rw-r--r-- | libhb/decsub.c | 5 | ||||
-rw-r--r-- | libhb/internal.h | 2 | ||||
-rw-r--r-- | libhb/reader.c | 4 | ||||
-rw-r--r-- | libhb/sync.c | 225 | ||||
-rw-r--r-- | libhb/work.c | 7 |
7 files changed, 213 insertions, 43 deletions
diff --git a/libhb/deca52.c b/libhb/deca52.c index de33b3e06..94bf8a540 100644 --- a/libhb/deca52.c +++ b/libhb/deca52.c @@ -27,6 +27,8 @@ struct hb_work_private_s int64_t next_expected_pts; + int64_t sequence; + uint8_t frame[3840]; hb_list_t * list; @@ -79,6 +81,7 @@ int deca52Init( hb_work_object_t * w, hb_job_t * job ) pv->level = 32768.0; pv->next_expected_pts = 0; + pv->sequence = 0; return 0; } @@ -109,13 +112,19 @@ int deca52Work( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_work_private_t * pv = w->private_data; hb_buffer_t * buf; + if( buf_in && *buf_in ) + { + pv->sequence = (*buf_in)->sequence; + } + hb_list_add( pv->list, *buf_in ); *buf_in = NULL; /* If we got more than a frame, chain raw buffers */ *buf_out = buf = Decode( w ); while( buf ) - { + { + buf->sequence = pv->sequence; buf->next = Decode( w ); buf = buf->next; } diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c index 0c5d2ecf6..e2deae0ce 100644 --- a/libhb/decmpeg2.c +++ b/libhb/decmpeg2.c @@ -151,6 +151,8 @@ 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; + buf->sequence = buf_es->sequence; + // Was a good break point found? if( chap_break ) { diff --git a/libhb/decsub.c b/libhb/decsub.c index 2b76ecf29..209c1c80f 100644 --- a/libhb/decsub.c +++ b/libhb/decsub.c @@ -95,6 +95,11 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, /* We got a complete subtitle, decode it */ *buf_out = Decode( w ); + if( buf_out && *buf_out ) + { + (*buf_out)->sequence = in->sequence; + } + /* Wait for the next one */ pv->size_sub = 0; pv->size_got = 0; diff --git a/libhb/internal.h b/libhb/internal.h index d3bbb637d..47138f2d2 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -35,6 +35,8 @@ struct hb_buffer_s uint8_t * data; int cur; + int64_t sequence; + int id; int64_t start; int64_t stop; diff --git a/libhb/reader.c b/libhb/reader.c index 2fd39eb63..4ced0a611 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -15,6 +15,8 @@ typedef struct hb_dvd_t * dvd; hb_buffer_t * ps; hb_stream_t * stream; + + uint sequence; } hb_reader_t; @@ -38,6 +40,7 @@ hb_thread_t * hb_reader_init( hb_job_t * job ) r->job = job; r->title = job->title; r->die = job->die; + r->sequence = 0; return hb_thread_init( "reader", ReaderFunc, r, HB_NORMAL_PRIORITY ); @@ -153,6 +156,7 @@ static void ReaderFunc( void * _r ) { hb_snooze( 50 ); } + buf->sequence = r->sequence++; hb_fifo_push( fifo, buf ); } else diff --git a/libhb/sync.c b/libhb/sync.c index 9c6624555..bb940790e 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -42,6 +42,7 @@ struct hb_work_private_s int64_t pts_offset_old; int64_t count_frames; int64_t count_frames_max; + int64_t video_sequence; hb_buffer_t * cur; /* The next picture to process */ /* Audio */ @@ -106,6 +107,8 @@ int syncInit( hb_work_object_t * w, hb_job_t * job ) /* Get subtitle info, if any */ pv->subtitle = hb_list_item( title->list_subtitle, 0 ); + pv->video_sequence = 0; + return 0; } @@ -144,9 +147,14 @@ void syncClose( hb_work_object_t * w ) * Work *********************************************************************** * The root routine of this work abject + * + * The way this works is that we are syncing the audio to the PTS of + * the last video that we processed. That's why we skip the audio sync + * if we haven't got a valid PTS from the video yet. + * **********************************************************************/ int syncWork( hb_work_object_t * w, hb_buffer_t ** unused1, - hb_buffer_t ** unused2 ) + hb_buffer_t ** unused2 ) { hb_work_private_t * pv = w->private_data; int i; @@ -294,6 +302,13 @@ static int SyncVideo( hb_work_object_t * w ) pv->pts_offset = cur->start; } + /* + + * Track the video sequence number localy so that we can sync the audio + * to it using the sequence number as well as the PTS. + */ + pv->video_sequence = cur->sequence; + /* Check for PTS jumps over 0.5 second */ if( next->start < cur->start - PTS_DISCONTINUITY_TOLERANCE || next->start > cur->start + PTS_DISCONTINUITY_TOLERANCE ) @@ -301,12 +316,26 @@ static int SyncVideo( hb_work_object_t * w ) hb_log( "Sync: Video PTS discontinuity (current buffer start=%lld, next buffer start=%lld), trash Video", cur->start, next->start ); - /* Trash all subtitles */ + /* + * Do we need to trash the subtitle, is it from the next->start period + * or is it from our old position. If the latter then trash it. + */ if( pv->subtitle ) { - while( ( sub = hb_fifo_get( pv->subtitle->fifo_raw ) ) ) + while( ( sub = hb_fifo_see( pv->subtitle->fifo_raw ) ) ) { - hb_buffer_close( &sub ); + if( ( sub->start > ( cur->start - PTS_DISCONTINUITY_TOLERANCE ) ) && + ( sub->start < ( cur->start + PTS_DISCONTINUITY_TOLERANCE ) ) ) + { + /* + * The subtitle is from our current time region which we are + * jumping from. So trash it as we are about to jump backwards + * or forwards and don't want it blocking the subtitle fifo. + */ + hb_log("Trashing subtitle 0x%x due to PTS discontinuity", sub); + sub = hb_fifo_get( pv->subtitle->fifo_raw ); + hb_buffer_close( &sub ); + } } } @@ -321,6 +350,8 @@ static int SyncVideo( hb_work_object_t * w ) pv->pts_offset_old = pv->pts_offset; pv->pts_offset = cur->start - pv->count_frames * pv->job->vrate_base / 300; + + pv->video_sequence = cur->sequence; continue; } @@ -336,20 +367,121 @@ static int SyncVideo( hb_work_object_t * w ) if( sub2 && sub->stop > sub2->start ) sub->stop = sub2->start; - if( sub->stop > cur->start ) + // hb_log("0x%x: video seq: %lld subtitle sequence: %lld", + // sub, cur->sequence, sub->sequence); + + if( sub->sequence > cur->sequence ) + { + /* + * The video is behind where we are, so wait until + * it catches up to the same reader point on the + * DVD. Then our PTS should be in the same region + * as the video. + */ + sub = NULL; break; + } - /* The subtitle is older than this picture, trash it */ + if( sub->stop > cur->start ) { + /* + * The stop time is in the future, so fall through + * and we'll deal with it in the next block of + * code. + */ + break; + } + else + { + /* + * The stop time is in the past. But is it due to + * it having been played already, or has the PTS + * been reset to 0? + */ + if( ( cur->start - sub->stop ) > PTS_DISCONTINUITY_TOLERANCE ) { + /* + * There is a lot of time between our current + * video and where this subtitle is ending, + * assume that we are about to reset the PTS + * and do not throw away this subtitle. + */ + break; + } + } + + /* + * The subtitle is older than this picture, trash it + */ sub = hb_fifo_get( pv->subtitle->fifo_raw ); hb_buffer_close( &sub ); } - /* If we have subtitles left in the fifo, check if we should - apply the first one to the current frame or if we should - keep it for later */ - if( sub && sub->start > cur->start ) + /* + * There is a valid subtitle, is it time to display it? + */ + if( sub ) { - sub = NULL; + if( sub->stop > sub->start) + { + /* + * Normal subtitle which ends after it starts, check to + * see that the current video is between the start and end. + */ + if( cur->start > sub->start && + cur->start < sub->stop ) + { + /* + * We should be playing this, so leave the + * subtitle in place. + * + * fall through to display + */ + } + else + { + /* + * Defer until the play point is within the subtitle + */ + sub = NULL; + } + } + else + { + /* + * The end of the subtitle is less than the start, this is a + * sign of a PTS discontinuity. + */ + if( sub->start > cur->start ) + { + /* + * we haven't reached the start time yet, or + * we have jumped backwards after having + * already started this subtitle. + */ + if( cur->start < sub->stop ) + { + /* + * We have jumped backwards and so should + * continue displaying this subtitle. + * + * fall through to display. + */ + } + else + { + /* + * Defer until the play point is within the subtitle + */ + sub = NULL; + } + } else { + /* + * Play this subtitle as the start is greater than our + * video point. + * + * fall through to display/ + */ + } + } } } @@ -357,6 +489,9 @@ static int SyncVideo( hb_work_object_t * w ) pts_expected = pv->pts_offset + pv->count_frames * pv->job->vrate_base / 300; + //hb_log("Video expecting PTS %lld, current frame: %lld, next frame: %lld, cf: %lld", + // pts_expected, cur->start, next->start, pv->count_frames * pv->job->vrate_base / 300 ); + if( cur->start < pts_expected - pv->job->vrate_base / 300 / 2 && next->start < pts_expected + pv->job->vrate_base / 300 / 2 ) { @@ -376,7 +511,8 @@ static int SyncVideo( hb_work_object_t * w ) /* We'll need the current frame more than one time. Make a copy of it and keep it */ buf_tmp = hb_buffer_init( cur->size ); - memcpy( buf_tmp->data, cur->data, cur->size ); + memcpy( buf_tmp->data, cur->data, cur->size ); + buf_tmp->sequence = cur->sequence; } else { @@ -468,52 +604,61 @@ static void SyncAudio( hb_work_object_t * w, int i ) /* The PTS of the samples we are expecting now */ pts_expected = pv->pts_offset + sync->count_frames * 90000 / rate; - /* - * Using the same logic as the Video have we crossed a VOB boundary as detected - * by the expected PTS and the PTS of our audio being out by more than the tolerance - * value. - */ + // hb_log("Video Sequence: %lld, Audio Sequence: %lld", pv->video_sequence, buf->sequence); + /* + * Using the same logic as the Video have we crossed a VOB + * boundary as detected by the expected PTS and the PTS of our + * audio being out by more than the tolerance value. + */ if( ( buf->start > pts_expected + PTS_DISCONTINUITY_TOLERANCE || buf->start < pts_expected - PTS_DISCONTINUITY_TOLERANCE ) && pv->pts_offset_old > INT64_MIN ) { /* - * Useful debug, but too verbose for normal use. - hb_log("Sync: Audio discontinuity (%lld < %lld < %lld)", + * Useful debug, but too verbose for normal use. + */ + hb_log("Sync: Audio discontinuity (sequence: vid %lld aud %lld) (pts %lld < %lld < %lld)", + pv->video_sequence, buf->sequence, pts_expected - PTS_DISCONTINUITY_TOLERANCE, buf->start, pts_expected + PTS_DISCONTINUITY_TOLERANCE ); - */ /* There has been a PTS discontinuity, and this frame might be from before the discontinuity*/ pts_expected = pv->pts_offset_old + sync->count_frames * 90000 / rate; - /* - * Is the audio from a valid period given the previous Video PTS. I.e. has there - * just been a video PTS discontinuity and this audio belongs to the vdeo from - * before? - */ + /* + * Is the audio from a valid period given the previous + * Video PTS. I.e. has there just been a video PTS + * discontinuity and this audio belongs to the vdeo from + * before? + */ if( buf->start > pts_expected + PTS_DISCONTINUITY_TOLERANCE || buf->start < pts_expected - PTS_DISCONTINUITY_TOLERANCE ) { - /* - * It's outside of our tolerance for where the video is now, and it's outside - * of the tolerance for where we have been in the case of a VOB change. - * Try and reconverge regardless. so continue on to our convergence - * code below which will kick in as it will be more than 100ms out. - * - * Note that trashing the Audio could make things worse if the Audio is in - * front because we will end up diverging even more. We need to hold on - * to the audio until the video catches up. - */ - hb_log("Sync: Audio is way out of sync, attempt to reconverge from current video PTS"); + /* + * It's outside of our tolerance for where the video + * is now, and it's outside of the tolerance for + * where we have been in the case of a VOB change. + * Try and reconverge regardless. so continue on to + * our convergence code below which will kick in as + * it will be more than 100ms out. + * + * Note that trashing the Audio could make things + * worse if the Audio is in front because we will end + * up diverging even more. We need to hold on to the + * audio until the video catches up. + */ + hb_log("Sync: Audio is way out of sync, attempt to reconverge from current video PTS"); - /* - * It wasn't from the old place, so we must be from the new, but just too far out. So attempt to - * reconverge by resetting the point we want to be to where we are currently wanting to be. - */ + /* + * It wasn't from the old place, so we must be from + * the new, but just too far out. So attempt to + * reconverge by resetting the point we want to be to + * where we are currently wanting to be. + */ pts_expected = pv->pts_offset + sync->count_frames * 90000 / rate; + start = pts_expected - pv->pts_offset; } else { /* Use the older offset */ start = pts_expected - pv->pts_offset_old; diff --git a/libhb/work.c b/libhb/work.c index 8bf8a4eac..535deb0fe 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -617,9 +617,12 @@ static void do_job( hb_job_t * job, int cpu_count ) subtitle_lowest_id = subtitle->id; } - if ( subtitle->forced_hits > 0 ) + if( subtitle->forced_hits > 0 ) { - subtitle_forced_id = subtitle->id; + if( subtitle_forced_id == 0 ) + { + subtitle_forced_id = subtitle->id; + } } } |