summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjbrjake <[email protected]>2009-06-04 17:52:01 +0000
committerjbrjake <[email protected]>2009-06-04 17:52:01 +0000
commita9eb0fba5299b12a951f2116276ef3382c1ff50a (patch)
treea4ee5ec78bca4077b8de2c522ee600824ff1696e
parent2c5699a0b597b55a6c6f7cc663e473dd4a7345e1 (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.c14
-rw-r--r--libhb/encx264.c27
-rw-r--r--libhb/hb.c13
-rw-r--r--libhb/hb.h13
-rw-r--r--libhb/render.c5
-rw-r--r--libhb/sync.c49
-rw-r--r--libhb/work.c24
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" );