diff options
author | jbrjake <[email protected]> | 2009-06-04 17:52:01 +0000 |
---|---|---|
committer | jbrjake <[email protected]> | 2009-06-04 17:52:01 +0000 |
commit | a9eb0fba5299b12a951f2116276ef3382c1ff50a (patch) | |
tree | a4ee5ec78bca4077b8de2c522ee600824ff1696e | |
parent | 2c5699a0b597b55a6c6f7cc663e473dd4a7345e1 (diff) |
Adds an interjob structure to preserve some encode data across jobs within an instance of libhb. This allows correcting the estimated bitrate/filesize of 2-pass encodes of variable framerate content, as the actual frame count is known after the first pass. Thanks for putting the idea into code, Shaya.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2482 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | libhb/common.c | 14 | ||||
-rw-r--r-- | libhb/encx264.c | 27 | ||||
-rw-r--r-- | libhb/hb.c | 13 | ||||
-rw-r--r-- | libhb/hb.h | 13 | ||||
-rw-r--r-- | libhb/render.c | 5 | ||||
-rw-r--r-- | libhb/sync.c | 49 | ||||
-rw-r--r-- | libhb/work.c | 24 |
7 files changed, 123 insertions, 22 deletions
diff --git a/libhb/common.c b/libhb/common.c index 350132bae..cea4a5064 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -9,6 +9,7 @@ #include <sys/time.h> #include "common.h" +#include "hb.h" /********************************************************************** * Global variables @@ -215,9 +216,21 @@ int hb_calc_bitrate( hb_job_t * job, int size ) length += 135000; length /= 90000; + if( size == -1 ) + { + hb_interjob_t * interjob = hb_interjob_get( job->h ); + avail = job->vbitrate * 125 * length; + avail += length * interjob->vrate * overhead / interjob->vrate_base; + } + /* Video overhead */ avail -= length * job->vrate * overhead / job->vrate_base; + if( size == -1 ) + { + goto ret; + } + for( i = 0; i < hb_list_count(job->list_audio); i++ ) { /* Audio data */ @@ -266,6 +279,7 @@ int hb_calc_bitrate( hb_job_t * job, int size ) avail -= length * audio->config.out.samplerate * overhead / samples_per_frame; } +ret: if( avail < 0 ) { return 0; diff --git a/libhb/encx264.c b/libhb/encx264.c index d00479468..880ca23ed 100644 --- a/libhb/encx264.c +++ b/libhb/encx264.c @@ -98,15 +98,28 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job ) */ if (job->vrate_base != 1080000) { - int fps = job->vrate / job->vrate_base; - - /* adjust +1 when fps has remainder to bump { 23.976, 29.976, 59.94 } to { 24, 30, 60 } */ - if (job->vrate % job->vrate_base) - fps += 1; + if (job->pass == 2 && !job->cfr ) + { + /* Even though the framerate might be different due to VFR, + we still want the same keyframe intervals as the 1st pass, + so the 1st pass stats won't conflict on frame decisions. */ + hb_interjob_t * interjob = hb_interjob_get( job->h ); + param.i_keyint_min = ( interjob->vrate / interjob->vrate_base ) + 1; + param.i_keyint_max = ( 10 * interjob->vrate / interjob->vrate_base ) + 1; + } + else + { + int fps = job->vrate / job->vrate_base; - param.i_keyint_min = fps; - param.i_keyint_max = fps * 10; + /* adjust +1 when fps has remainder to bump + { 23.976, 29.976, 59.94 } to { 24, 30, 60 } */ + if (job->vrate % job->vrate_base) + fps += 1; + param.i_keyint_min = fps; + param.i_keyint_max = fps * 10; + } + hb_log("encx264: keyint-min: %i, keyint-max: %i", param.i_keyint_min, param.i_keyint_max); } diff --git a/libhb/hb.c b/libhb/hb.c index aa6679193..f5caa8cd6 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -38,6 +38,11 @@ struct hb_handle_s /* For MacGui active queue increments each time the scan thread completes*/ int scanCount; + + /* Stash of persistent data between jobs, for stuff + like correcting frame count and framerate estimates + on multi-pass encodes where frames get dropped. */ + hb_interjob_t * interjob; }; @@ -142,6 +147,8 @@ hb_handle_t * hb_init( int verbose, int update_check ) h->pause_lock = hb_lock_init(); + h->interjob = calloc( sizeof( hb_interjob_t ), 1 ); + /* libavcodec */ hb_avcodec_init(); @@ -1475,3 +1482,9 @@ void hb_set_state( hb_handle_t * h, hb_state_t * s ) hb_unlock( h->state_lock ); hb_unlock( h->pause_lock ); } + +/* Passes a pointer to persistent data */ +hb_interjob_t * hb_interjob_get( hb_handle_t * h ) +{ + return h->interjob; +} diff --git a/libhb/hb.h b/libhb/hb.h index cc7a7eecc..080d9795e 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -70,6 +70,19 @@ void hb_pause( hb_handle_t * ); void hb_resume( hb_handle_t * ); void hb_stop( hb_handle_t * ); +/* Persistent data between jobs. */ +typedef struct hb_interjob_s +{ + int last_job; /* job->sequence_id & 0xFFFFFF */ + int frame_count; /* number of frames counted by sync */ + uint64_t total_time; /* real length in 90khz (i.e. / 90000 */ + int render_dropped; /* frames droped by telecine */ + int vrate; /* initial assigned vrate */ + int vrate_base; /* initial assigned vrate_base */ +} hb_interjob_t; + +hb_interjob_t * hb_interjob_get( hb_handle_t * ); + /* hb_get_state() Should be regularly called by the UI (like 5 or 10 times a second). Look at test/test.c to see how to use it. */ diff --git a/libhb/render.c b/libhb/render.c index fefec7792..34928d906 100644 --- a/libhb/render.c +++ b/libhb/render.c @@ -668,6 +668,11 @@ void renderClose( hb_work_object_t * w ) pv->count_frames, pv->drops, pv->dups ); } + hb_interjob_t * interjob = hb_interjob_get( w->private_data->job->h ); + + /* Preserve dropped frame count for more accurate framerates in 2nd passes. */ + interjob->render_dropped = pv->dropped_frames; + hb_log("render: lost time: %lld (%i frames)", pv->total_lost_time, pv->dropped_frames); hb_log("render: gained time: %lld (%i frames) (%lld not accounted for)", pv->total_gained_time, pv->extended_frames, pv->total_lost_time - pv->total_gained_time); if (pv->dropped_frames) diff --git a/libhb/sync.c b/libhb/sync.c index 8ae1b78e8..abcf11141 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -96,28 +96,37 @@ int syncInit( hb_work_object_t * w, hb_job_t * job ) pv->job = job; pv->pts_offset = INT64_MIN; - /* Calculate how many video frames we are expecting */ - if (job->pts_to_stop) + if( job->pass == 2 ) { - duration = job->pts_to_stop + 90000; - } - else if( job->frame_to_stop ) - { - /* Set the duration to a rough estimate */ - duration = ( job->frame_to_stop / ( job->vrate / job->vrate_base ) ) * 90000; + /* We already have an accurate frame count from pass 1 */ + hb_interjob_t * interjob = hb_interjob_get( job->h ); + pv->count_frames_max = interjob->frame_count; } else { - duration = 0; - for( i = job->chapter_start; i <= job->chapter_end; i++ ) + /* Calculate how many video frames we are expecting */ + if ( job->pts_to_stop ) + { + duration = job->pts_to_stop + 90000; + } + else if( job->frame_to_stop ) + { + /* Set the duration to a rough estimate */ + duration = ( job->frame_to_stop / ( job->vrate / job->vrate_base ) ) * 90000; + } + else { - chapter = hb_list_item( title->list_chapter, i - 1 ); - duration += chapter->duration; + duration = 0; + for( i = job->chapter_start; i <= job->chapter_end; i++ ) + { + chapter = hb_list_item( title->list_chapter, i - 1 ); + duration += chapter->duration; + } + duration += 90000; + /* 1 second safety so we're sure we won't miss anything */ } - duration += 90000; - /* 1 second safety so we're sure we won't miss anything */ + pv->count_frames_max = duration * job->vrate / job->vrate_base / 90000; } - pv->count_frames_max = duration * job->vrate / job->vrate_base / 90000; hb_log( "sync: expecting %d video frames", pv->count_frames_max ); pv->busy |= 1; @@ -156,6 +165,16 @@ void syncClose( hb_work_object_t * w ) hb_log( "sync: got %d frames, %d expected", pv->count_frames, pv->count_frames_max ); + /* save data for second pass */ + if( job->pass == 1 ) + { + /* Preserve frame count for better accuracy in pass 2 */ + hb_interjob_t * interjob = hb_interjob_get( job->h ); + interjob->frame_count = pv->count_frames; + interjob->last_job = job->sequence_id; + interjob->total_time = pv->next_start; + } + if (pv->drops || pv->dups ) { hb_log( "sync: %d frames dropped, %d duplicated", pv->drops, pv->dups ); diff --git a/libhb/work.c b/libhb/work.c index 5be4bdf9f..92f04f483 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -335,6 +335,25 @@ void hb_display_job_info( hb_job_t * job ) } } +/* Corrects framerates when actual duration and frame count numbers are known. */ +void correct_framerate( hb_job_t * job ) +{ + int real_frames; + + hb_interjob_t * interjob = hb_interjob_get( job->h ); + + if( ( job->sequence_id & 0xFFFFFF ) != ( interjob->last_job ) ) + return; // Interjob information is for a different encode. + + /* Cache the original framerate before altering it. */ + interjob->vrate = job->vrate; + interjob->vrate_base = job->vrate_base; + + real_frames = interjob->frame_count - interjob->render_dropped; + job->vrate = job->vrate_base * ( real_frames / ( interjob->total_time / 90000 ) ); +} + + /** * Job initialization rountine. * Initializes fifos. @@ -363,6 +382,11 @@ static void do_job( hb_job_t * job, int cpu_count ) title = job->title; + if( job->pass == 2 && !job->cfr ) + { + correct_framerate( job ); + } + job->list_work = hb_list_init(); hb_log( "starting job" ); |